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.
- 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.
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!!
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!!
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?
- You code locally (create tests, classes, etc).
- You commit code.
- You push your code (or do a pull request).
- 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).
- Jenkins receives a notification that a repository included in a pipeline has received a push.
- Jenkins pulls every change to the repository in Jenkins workspace.
- Jenkins starts the pipeline associated with that repository.
- The Pipeline builds the project.
- The Pipeline runs the tests while doing code coverage.
- The Pipeline shows build status and tests reports.
- 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.
- Install required programs.
- Create Unreal Project.
- Add .gitignore.
- Add Jenkinsfile and push changes.
- Create a class (without parent, None) from the UE Editor, place it in a separate 'Tests' folder and use it as a test class.
- Create tests.
- 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).
- Create Jenkins Multibranch Pipeline project.
- Create a tunnel via ngrok to the Jenkins port (default is 8080).
- 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!!!).
- 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).
- 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.
The following is a list of resources that helped me while doing this project.
- Test-Driven Development - Wikipedia
- Self Testing Code - Martin Fowler
- Test-Driven Development - Martin Fowler
- Continuous Integration - Wikipedia
- Continuous Integration - Martin Fowler
- Continuous Integration - Thoughtworks
- Continuous Delivery - Martin Fowler
- Continuous Integration vs. Continuous Delivery vs. Continuous Deployment - Atlassian
- Extra: Branching Patterns - Martin Fowler
- How force Jenkins to show UI always in English? Issue - Superuser - sobi3ch
- Jenkins Automated Build Trigger On Github Pull Request - DevOpsCube
- Jenkins Multibranch Pipeline Tutorial For Beginners - DevOpsCube
- Pipeline - Jenkins
- Pipeline Syntax - Jenkins
- Pipeline Syntax: Agent - Jenkins
- Pipeline Examples - Jenkins
- Using a Jenkinsfile - Jenkins
- Jenkins : how to print the contents of a text file to the build log? Issue - StackOverflow - AnneTheAgile
- jenkins pipeline: agent vs node? Issue - StackOverflow - Matthias M
- How do I make Jenkins pipeline run in (any) agent machine, but never master? Issue - StackOverflow - Joshua Fox
- Why our batch process works locally and not from Jenkins? - CloudBees
- Jenkins CI Pipeline Scripts not permitted to use method groovy.lang.GroovyObject Issue - StackOverflow - Daniel Hernández
- Processing XML - Apache Groovy
- Jenkins Workflow-Plugin and Groovy Libs Issue - StackOverflow - Rene
- Send Slack Notifications with Jenkins - Venessa Yeh
- Use emoji and emoticons - Slack
- Emoji Cheat Sheet - Webfx
- Slack Notification Plugin - Jenkins
- Color Hex Color Codes - color-hex
- ngrok Official page
- An ngrok Tutorial and Primer - Daniel Miessler
- Secure localhost tunnels with ngrok - Atlassian
- Creating Webhooks - GitHub
- Triggering a Jenkins build on push using GitHub webhooks - Parul Dixit
- Github webhook with local Jenkins and ngrok Issue - StackOverflow - Pruitlgoe
- Github Webhook With Jenkins return 302 NotFound Issue - StackOverflow - Xiaoxi Bian
- Automation System Overview - Epic Games
- Automation System User Guide
- Automation Technical Guide - Epic Games
- How Rare Tests Sea of Thieves to Stop Bugs Reaching Players | AI and Games - YouTube
- Automated Testing at Scale in Sea of Thieves | Unreal Fest Europe 2019 | Unreal Engine - YouTube - Jessica Baker
- Tech Blog: Tests and Testability - Rare - Jessica Baker
- Continuous Delivery in Games - Jafar Soltani
- Tech Blog: Adopting Continuous Delivery (Part 1) - Rare - Jafar Soltani
- Tech Blog: Adopting Continuous Delivery (Part 2) - Rare - Jafar Soltani
- Tech Blog: Adopting Continuous Delivery (Part 3) - Rare - Jafar Soltani
- Automated Testing of Gameplay Features in 'Sea of Thieves' - Robert Masella
- Automation with Unreal Engine and Jenkins-CI - Patrice Vignola
- Unreal Build Automation and Deployment at ExtroForge - ExtroForge
- Jenkins CI Automation for Unreal Engine 4 Projects - GitHub - Skymap Games
- UE4 Unit Tests in Jenkins - Michael Delva
- UE4 Automation Tool - Jonathan Hale
- Who has the latest Unreal Engine 4 Console Variables and Commands? Can you share it with me? Issue - Unreal Engine Forums - GaoHeShun
- Command-Line Arguments - Epic Games
- Console Variables in C++ - Epic Games
- Automate deployment with the Unreal Engine using the Unreal Automation Tool (UAT) - Marvin Pohl
- Unit Tests in Unreal – pt 1 – A definition of Unit Tests for this series - Eric Lemes
- Simple Automation Test on Dedicated Server Build Issue - rjjatson
- Run automated testing from command line Discussion - nikitablack
- Unreal Engine 4. Different ways to instantiate the object Discussion - StackOverflow - raviga
- Unreal Containers (future use)
- Pass Command Line arguments (Parameters) to a Windows batch file - ss64
- Remove Quotes from a string - ss64
- Setting variables - ss64
- Defining and using a variable in batch file - StackOverflow - Jamie Dixon
(more to come, maybe)
Alberto Mikulan, alberto.mikulan@gmail.com