Git hook for Visual Studio tests

Hi guys! The time has come, that I felt the urge to write some unit tests. I know, I know, you’ll tell me that I should already have a project full of great TDD or DDD (or both) style tests, but I really didn’t grasp a concept of testing in Unity. I was even planning on catching up on that topic, so I watched a 1-hour tutorial about Unity Test Tools, but it looks terribly complex and confusing. I felt like this was useful for quick bug-searching, not for writing hundreds of tests that would be run frequently.

That’s why I did it my way. It’s not rocket science – I use MS Test and my beloved FluentAssertions library for neat assertions (object.property.Should().NotBeNull() – something like that).

It has some drawbacks, though – in the unit tests project there must be no references to any parts of the UnityEngine code, so great code separation is needed. If you accidentally included some of this code, you’d get some nasty SecurityException (“Ecall methods must be packaged into a system module” – guess why I know this that well… xD ).

Additionally, I usually open the solution using the “Open C# project” from the Assets menu in Unity and I have to manually attach this tests project to the solution every time is it opened. But still – I needed to check some problematic integration problems and unit tests proved invaluable.

As this is my pet project, I can test everything that intrigues me on it. Recently I heard about git hooks and how can running unit test be forced by Git itself, so I wanted to give it a try.

Git hooks

Git hooks are small scripts that Git can run in special time moments – for example before commit, before push, after merge, etc. To start using them, you need to navigate to .git/hooks, choose the action that you’d like to hook on, modify the script so that it does what you want and rename it, deleting the .sample part of the filename.

I wanted to use these hooks to run my tests at special moments. Since this is a good practice to commit changes frequently and unit tests in Visual Studio take some time, I wouldn’t like to complicate this activity by firing tests. However, it is nice knowing that at the moment of The Push, all of the tests pass smoothly. Of course we can remember to run them manually, but it sometimes tempting to avoid that (“that change is so small, it certainly won’t do any harm”). We also do not always have a great Continuous Integration server set up, that would do that for us… That is why I decided to hook on pre-push.

Running MS tests from command line

Git hooks are simple bash scripts –the result it determined by the exit code (0 means everything is ok and Git can proceed with the operation, 1 indicates some failures). That is why I needed a way to run my tests from command line and find out what was the result.

This can be done using two little runners provided with Visual Studio – older one MSTest.exe tried copying references in some other output directory, which caused failures in my case. The newer one - vstest.console.exe worked like a charm though. I requires only one parameter – the dll file that is a result of building the tests project.

The script

There were many little catches that caused some problems for me, but the result script is really tiny and straightforward:

• I echo the information that the script started running, because running tests can take some time and there is no partial result displayed,

• The location of the test runner program may be different in your case,

• Path to the test dll can be relative, but has to start without the slash,

• The core part of the script is invoking the test program and greping the output for the “Failed: 0” string, which indicates that all of the test passed. This output is saved in a variable. In the next step number of lines is counted, if it’s greater than zero we exit cleanly, otherwise the error result is returned,

• Remember that there must be no whitespaces in assignment operations! (test_runner =”…” won’t work),

• Hook scripts aren’t committed.

Results

This is how it looks like when tests don’t pass:

We can see that the exception is written out along with our script’s message about the failure. As expected, the push is aborted. Otherwise, everything goes smoothly:

Since this is my first time playing with Git hooks, I am curious whether you use it too – what are other interesting use cases? Do you have a fixed set of hooks that you copy among projects?

As always – if you find this post helpful and would like to get notified when future ones appear, like my fan page or follow me on Twitter. (｡◕‿◕｡)