The Road to Continuous Integration in Unity
Create a simple project in GitHub and use Unity to perform Continuous Integration operations on your pipeline.
Join the DZone community and get the full member experience.
Join For FreeHave you ever had a doubt while developing a new feature? The doubt that tells you what you are doing could break something within the project? Or worse, you don’t have that doubt and you make the project explode anyway?
In this first part, we will explain what Continuous Integration is and how it can help us. At the end of the post, we will have Unity tests running in every change we make into our project using Gitlab CI/CD.
Wait! Continuous Integration? Yeah, I Know…
Continuous Integration is the methodology of integrating, testing and building our application in each change we make to our version control automatically.
- Integrate: to upload our changes to the repository we work in, for example, Gitlab, Github, etc., to its main branch, usually master (Git Flow) or trunk (Trunk-based development).
- Test: to run all unit tests of our application.
- Build: to build the artifact of our product, for example: .apk, .ipa, .exe, jar, etc.
Why CI?
Without continuous integration, your software is broken until somebody proves it works, usually during a testing or integration stage. —Jez Humble & David Farley, Continuous Delivery
Continuous Integration, in combination with other practices such as TDD (Test Driven Development), increases our confidence in the code. And one of the main values of CI is fast feedback.
Some time ago I worked in a company where we did not practice Continuous Integration, nor did we test our products. The team members took days to upload their changes to the control version (SVN) and my Fridays were stressful days of merging and building. Being all manual, I had to resolve the different conflicts that were arising and prepare the device to show the product at the meeting. Sometimes, it happened that we couldn't get together because the build was completely broken. If only we had that feedback before, the errors could have been resolved in time.
Thanks to the quick feedback that CI gives us, we can detect if there is an error in our code, whether a test or our build has failed. In that case, we should stop doing what we are doing to fix the situation and keep our project always in green.
What are we waiting for? Let’s get started!
As I said at the beginning, we will use Unity + Gitlab CI / CD. If you do not have an account on gitlab.com, create one.
Have you signed up already? Let’s keep going…
Gitlab Setup
Let’s create a simple project in the repository.
Now let’s clone our project using the clone button GitLab provides.
Unity Setup
And now Unity! Let’s create a new project in the folder you just cloned. I will create a Unity project quickly creating the Assets and ProjectSettings folder. (Did you know that?)
And now we have to create a Test! Let’s create a script under the Assets/Editor folder.
using NUnit.Framework;
public class SomeGreenTest
{
[Test]
public void SomeGreenTestPassing()
{
Assert.Pass();
}
}
Let’s verify that the test runs correctly in the Unity Test Runner.
Perfect! Now let’s upload our project to our repository! But first, since we are not going to upload everything we have in our folder, let’s create a .gitignore file in the root of our project.
.gitignore is the file that git uses to ignore files and therefore does not upload them to the repository.
I leave here the .gitignore
used to avoid uploading unnecessary files.
Library/
Temp/
*sln
*csproj
Logs/
obj/
.idea/
I will use the terminal to upload my files, but you can use the program you are used to.
If I go back to my panel in GitLab, I will find my versioned files:
Here comes the interesting part, so we will go step by step to understand.
Gitlab CI/CD Setup
In order for Gitlab to run Continuous Integration, you must create a configuration file called .GitLab-ci.yml and you need a machine where jobs will be executed (we will use ours). In this file, we will write the commands that our Runner (the machine where CI runs) must do. Here we will go fast, but I insist that you visit this page for more information about Gitlab CI / CD.
To begin with, I will create a small .gitlab-ci.yml in the project root simulating the different tasks to perform.
stages:
- test
- build
- deploy
unit-test:
stage: test
script: echo 'Testing...'
unity-build:
stage: build
script: echo 'Building...'
playstore:
stage: deploy
script: echo 'Deploying...'
What is each parameter?
- Pipeline is the connection of all the works and stages.
- Stages are like the categories of the pipeline, the different steps.
- Job is a particular task.
The .gitlab-ci.yml above has three stages (test, build, and deploy) and it has three different jobs, each belonging to a particular stage, and their job, for the moment, is to do an echo.
Let’s upload the change we just made to our repository.
git add .
git commit -m 'Added .gitlab-ci.yml'
git push
If we go to the Gitlab CI / CD tab, we will see the following page.
And we can even enter into the job unit-test and see what the runner is doing. Yes! We see the machine terminal.
Now you will surely wonder on which machine your pipeline is running?
Gitlab offers, by default, machines where some tasks can be executed, but in our case, we will need Unity installed, and Gitlab machines do not have it. For this, we will use our own machine! Yes, the same one you are using to see this post, unless you are using a cell phone or tablet.
In this case, we need to install gitlab-runner in our machine, a binary that Gitlab provides to us to register a machine as CI runner in our project.
You can follow the installation step by step by clicking here. Once installed, we need to register our runner. For that, we will do the following.
We have done several important things here.
- We registered the runner with a token that provides GitLab in the project configuration.
- We created the unity tag that we will use in a moment (our CI Runner will only execute jobs tagged as unity).
- We selected the executor shell. This means that we can run console commands.
The next step is to modify our .gitlab-ci.yml
to tag the jobs with the unity tag.
stages:
- test
- build
- deploy
unit-test:
script: "echo 'Testing...'"
stage: test
tags:
- unity
unity-build:
script: "echo 'Building...'"
stage: build
tags:
- unity
playstore:
script: "echo 'Deploying...'"
stage: deploy
tags:
- unity
Let’s upload the change and see what machine runs now.
git add .
git commit -m 'Added unity tag in .gitlab-ci.yml'
git push
Now that we have configured our machine as a Runner and it communicates in the tasks, it is time to put Unity to work!
I recommend you to read the Unity CLI documentation to understand what we will do next.
I will replace in my .gitlab-ci.yml the “echo testing” with the command line to run Unity tests in editor mode.
stages:
- test
- build
- deploy
unit-test:
script: "/Applications/Unity/Hub/Editor/2018.4.4f1/Unity.app/Contents/MacOS/Unity \
-batchmode \
-projectPath . \
-runTests -testPlatform editmode \
-logFile \
-testResults ./unit-tests.xml"
stage: test
tags:
- unity
unity-build:
script: "echo 'Building...'"
stage: build
tags:
- unity
playstore:
script: "echo 'Deploying...'"
stage: deploy
tags:
- unity
Let’s understand the command line:
- /Applications/Unity/Hub…: this is the path where the Unity executable is on my machine. Find where yours is and replace it.
- batchmode: Unity will run without human intervention, which means it will not show UI.
- projectPath: We will use “.” to say that our project is exactly where we are executing the process.
- runTest testPlatform: This is the command to execute the tests, in this case: “editmode.” It is also possible to run the playmode tests. (Cool, right?)
- logFile: it will show the output of the Unity process on the console, so we can see what it is doing.
- testResults: it is the path where the test results will be saved to.
git add .
git commit -m 'Added unity test CLI in .gitlab-ci.yml'
git push
You just ran the Unity tests on your machine! Don't believe me? Let’s change the test so it will fail.
using NUnit.Framework;
public class SomeGreenTest
{
[Test]
public void SomeGreenTestPassing()
{
Assert.Fail();
}
}
git add .
git commit -m 'Modified test to fail :('
git push
We have our environment ready so that in each change we make on our project, we run the tests to verify these changes. If it fails, an email will arrive and you will have to fix what you have broken; otherwise, the first part of our Continuous Integration is done! But it isn’t over yet. In the following post, we will see how to build Unity!
Summary
Using Continuous Integration provides a great advantage, whether you are a single developer or a team. In the next post, we will automate our builds every time we upload a new change.
Using or not CI makes a big difference in our developments. Therefore, it doesn’t matter if you are one person or a team, the advantages are very positive.
Remember these points:
Manual Integration
- The process is not guaranteed to be reliable, repetitive and clearly not automatic.
- If we do not test and build each of our changes, we do not know if our project works.
- There is a risk of skipping stages which does not make it reliable and may cause errors.
- Each step in the process has to be documented and yet it is not determined that who executes the process meets all of its steps.
- Doing repetitive tasks is boring!
Continuous Integration
- It helps create automatic, reliable and repetitive processes.
- Increase confidence in our projects.
- Reduces risks.
- The code is the documentation itself.
- Encourage collaboration, because everything is explicit in a script.
- Quick feedback
Opinions expressed by DZone contributors are their own.
Comments