/UE4-TDD-CI_Testing

Project Template to use on TDD and CI with Unreal Engine 4.

Primary LanguageC++

UE4 TDD CI Testing Template

Project Template to use on TDD and CI with Unreal Engine 4 on Windows.

This is the repository from the article Jenkins, CI and Test-Driven Development

Feel free to use it. If you have any questions, please let me know.

Requirements

  • Unreal Engine 4 (initially on 4.22, now on 4.25).
  • git.
  • github.
  • ngrok.
  • Jenkins.
  • OpenCppCoverage.

I assume you understand how Test-Driven Development (TDD) and Continuous Integration (CI) works. If not, check the resources section, it's a nice place to start and you can try tests with this project.

NEW: Do you want even MORE tests??

Since before creating this tutorial I've been working on my final project for university.

My project was about a simple racing videogame using TDD and CI as the environment.

I made it public so others will be able to have even more implementations of tests with TDD (over 340!!). It also has a slightly modified version of this project's jenkinsfile, replication tests over LAN and some helpful classes to aid on the tests.

Also, it has the logical view and a report (currently in Spanish but I'll upload the English version soon).

I hope this really helps in your projects! Enjoy!!

Project repository

Initial Tests

Inside the repository, there're some tests to simulate accelerating a pawn and simulating key presses!!!

This are inside the Tests folder of the project.

These tests use a void map to simulate everything needed.

Look into the commits to have a grasp of how the order is important to TDD (test first, implementation after test).

I think they'll be really useful and save you a lot of headaches, enjoy!!

Introduction

Unreal Engine provides a testing suite inside it's Automation Framework, but it's tedious to write a test, build the project, open the editor, run the tests and see if they pass or fail.

There's a way to do the tests more efficiently (you still have to create a class from within the editor to use it as a test class so the project 'sees' it), without having to wait the editor to finish and check the results for yourself.

What you need is Jenkins, an automation program that triggers a pipeline execution via an event. A pipeline is a configuration of a workspace environment, a series of stages, each of them consisting of a series of steps (calling batch files in windows, executing commands, printing logs, etc), and finally things that you do after (post) the pipeline is executed.

Inside that pipeline we're going to declare how to build the project, run our tests, check if they fail or pass and also which parts of the project aren't being tested (via code coverage).

How's the process then?

  1. You code locally (create tests, classes, etc).
  2. You commit code.
  3. You push your code (or do a pull request).
  4. Github receives the push and uses it's webhook to notify Jenkins via a tunnel created by ngrok (because we don't have a way to communicate directly with Jenkins).
  5. Jenkins receives a notification that a repository included in a pipeline has received a push.
  6. Jenkins pulls every change to the repository in Jenkins workspace.
  7. Jenkins starts the pipeline associated with that repository.
  8. The Pipeline builds the project.
  9. The Pipeline runs the tests while doing code coverage.
  10. The Pipeline shows build status and tests reports.
  11. Jenkins notifies Github the results of the pipeline build.

Looks easy, right? The only problem is understanding that Jenkins is meant to be used in a server, which means that it (and every application that the pipeline invokes) has to work in headless mode. Also, no application invoked has to have any input allowed.

This problem is a source of headaches in the beginning, but you'll become accustomed to it.

First Time Steps

  1. Install required programs.
  2. Create Unreal Project.
  3. Add .gitignore.
  4. Add Jenkinsfile and push changes.
  5. Create a class (without parent, None) from the UE Editor, place it in a separate 'Tests' folder and use it as a test class.
  6. Create tests.
  7. In Jenkins Install:
    • Blue Ocean plugin (there're plugins necessary with it and if you want a prettier Jenkins).
    • GitHub plugin (for pull requests).
    • HTTP request plugin (mm don't know if necessary, but it was some time ago).
    • Cobertura plugin (for code coverage).
    • Slack plugin and configure it (if you want slack notifications).
  8. Create Jenkins Multibranch Pipeline project.
  9. Create a tunnel via ngrok to the Jenkins port (default is 8080).
  10. Add a webhook to the github repository referencing the http given by ngrok (don't forget to add a forward slash '/' to the webhook trail if it doesn't have one!!!).
  11. Push to see the build trigger in Jenkins.

It would be nice to add github checks to pull requests, but it's not possible with a free account (in private repositories).

Jenkinsfile

  • I use node 'master' because I have only one pc for Jenkins.
  • I use a custom workspace (and at the beginning of the disk) because the Unreal Build Tool has problems with long filenames.
  • The environment variables are used as parameters, to avoid hardcoding.
  • BuildWithoutCooking.bat it's used to build the project. I don't use cooking because I think that process should be made in continuous delivery.
  • It's not necessary to create the Visual Studio files because we don't do anything with Visual Studio, we run the tests using the Unreal Automation Tool.
  • TestRunnerAndCodeCoverage uses OpenCppCodeCoverage (which does the code coverage) attached to the Unreal Engine Editor (which does the tests run).
  • TestRunnerAndCodeCoverage.bat assumes that you have a separate folder for tests (\Tests). This could be changed hardcoding it or adding another parameter to the batch file.
  • The Tests Report is made in JSon so we need to parse it to XML to be readable by JUnit. So, thanks to Michael Delva for his test report parser method found in his blogspot, I modified it only a little.
  • The CodeCoverageReport will be used by Cobertura to display the code coverage.
  • In some places, slackSend is used to send messages to a Slack Workspace. The channel name is only used if you want to override the one used in the Slack plugin configuration.
  • I do a git hard reset and git clean to clean the workspace after everything has been done. This way, if the repository it's something big, only the changes are downloaded and thus, we save bandwidth.

Resources

The following is a list of resources that helped me while doing this project.

TDD

CI

Jenkins

Slack notifications

ngrok

GitHub

OpenCppCoverage

UE4

BATCH

(more to come, maybe)

Alberto Mikulan, alberto.mikulan@gmail.com