Continuous Deployment FTW?
You’ve decided to use a continuous integration server (CI) as part of your DevOps lifecycle. You’re planning to approach things on a continuous deployment basis, specifically targeting a Microsoft Azure Web App Service server. Continuous deployment is indeed fantastic…but what if deployments are made when your unit tests are failing?
Enter “Appveyor” & “xUnit”…
I’ve covered Appveyor previously when discussing the downside of relying on using a single continuous integration framework for delivery. When it comes to testing, I’m sure you’re already aware of xUnit - An awesome unit testing framework and indeed my favourite to use of them all. I’ve mentioned xUnit previously both here and also here.
Rather than explaining continuous integration or YAML in detail, let’s dive straight in to the bit we’re most concerned about - unit testing pre-deployment!
I’m working on the assumption that you’re running ASP.Net MVC Core and have already setup a Microsoft Azure Web App Service, along with an Appveyor account that is bound to your Github repository and set to respond to all Git commits that you make to the master branch.
Head to Visual Studio and add a fresh xUnit “Test Project” class library -
Write some unit tests that are relevant to your projects features -
Your Visual Studio solution should now look something like this -
Immediately after our “build configuration”, but before our “artifacts configuration”, we need to add a simple “test configuration” which includes some additional YAML commands -
…Now to explain what the additional YAML commands (dotnet build and dotnet test) do. You’ll note that the path we are executing “dotnet build” against is the exact path of our xUnit test project within our Visual Studio solution (I’ve purposely stated the path directly for clarity). This command builds a project and all of its dependencies. It’s also worth nothing that “dotnet restore” is run implicitly when you execute “dotnet build” (as of .Net Core 2.0). “dotnet test” is the test driver that is used to execute all unit tests. So what we’re asking Appveyor to do here is “build our xUnit test project, and then execute the unit tests”.
Both our unit tests are set to pass, and pass locally, so lets commit the change to Github and watch Appveyor work its magic!
A successful test execution occurs, with all unit tests passing.
Deployment complete, build success. Due to all of our unit tests passing, Appveyor packages up our ASP.Net MVC Core website into an artifact and deploys it to our Microsoft Azure Web App Service.
If we view the “tests” tab in Appveyor, we can see our 2 successfully passing unit tests -
We can also view our website package on the “artifacts” tab.
….Now let’s break one of our unit tests by changing our expected result and see how Appveyor responds -
As you can see, at the point where Appveyor executed the “dotnet test” command, the broken unit test fails as expected, and the build ceases to deploy to our Microsoft Azure Web App Service.
…This is the result we were looking for, as it ensures we aren’t incorrectly deploying breaking changes to our live environment. Let’s have a quick look at the “tests” tab in Appveyor and see the result -
There’s our failing test, but what about the artifacts…we’re they created regardless of the failing unit test during the build process?
…No they weren’t, which helps ensure we aren’t accidentally deploying an artifact with failing unit tests.