Author: Roy Osherove
Pub Date: 2014
Size: 12 Mb
The Art of Unit Testing, Second Edition guides you step by step from writing your first simple tests to developing robust test sets that are maintainable, readable, and trustworthy. You’ll master the foundational ideas and quickly move to high-value subjects like mocks, stubs, and isolation, including frameworks such as Moq, FakeItEasy, and Typemock Isolator. You’ll explore test patterns and organization, working with legacy code, and even “untestable” code. Along the way, you’ll learn about integration testing and techniques and tools for testing databases and other technologies. You know you should be unit testing, so why aren’t you doing it? If you’re new to unit testing, if you find unit testing tedious, or if you’re just not getting enough payoff for the effort you put into it, keep reading. The Art of Unit Testing, Second Edition guides you step by step from writing your first simple unit tests to building complete test sets that are maintainable, readable, and trustworthy. You’ll move quickly to more complicated subjects like mocks and stubs, while learning to use isolation (mocking) frameworks like Moq, FakeItEasy, and Typemock Isolator. You’ll explore test patterns and organization, refactor code applications, and learn how to test “untestable” code. Along the way, you’ll learn about integration testing and techniques for testing with databases. The examples in the book use C#, but will benefit anyone using a statically typed language such as Java or C++.
– Create readable, maintainable, trustworthy tests
– Fakes, stubs, mock objects, and isolation (mocking) frameworks
– Simple dependency injection techniques
– Refactoring legacy code
Anatomy of a build script
I usually end up with several single-purpose build scripts. That kind of setup allows for better maintenance and coherency of the build process, and would include these scripts:
- A continuous integration (CI) build script
- A nightly build script
- A deployment build script
I like to separate them because I treat build scripts like small code functions that can be called with parameters and the current version of source code. The caller of these functions (scripts) is the CIserver.
A CIbuild script will usually, at the very least, compile the current sources in debug mode and run all the unit tests. Potentially it will also run other tests, as long as they’re fast. A CIbuild script is meant to give maximum information in the least amount of time. The quicker it is, the quicker you know you likely didn’t break anything and can get back to work.
A nightly build will usually take longer. I like to trigger it just after a CIbuild, to get even more feedback, but I won’t be waiting too eagerly for it and can continue coding while it’s running. It takes longer because it’s meant to do all the tasks that the CIbuild considered irrelevant or not important enough to be included in a quick feedback cycle of CI. These tasks can include almost anything but usually include compilation in release mode, running all the slow tests, and possibly deploying to test environments for the next day.
I call them nightly builds, but they can be run many times a day. At the very least, they run once a night. They give more feedback but take more time to give it.
A deployment build script is essentially a delivery mechanism. It’s triggered by the CIserver and can be as simple as an xcopyto a remote server or as complicated as deploying to hundreds of servers, reinitializing Azure or Amazon Elastic Compute Cloud (EC2) instances, and merging databases.
All builds usually notify the user by email if they break, but the ultimate required destination of notification is the caller of the build scripts: the CIserver.
There are many tools that can help you create an automated build system. Some are
free or open source, and some are commercial. Following are a few tools you can consider.
For build scripts:
- Visual Build Pro
- Travis CI
- Visual Studio Team Foundation Service
- ThoughtWorks Go
Some CIservers also allow creating build script-related tasks as a built-in feature. I try to stay away from using those features, because I want my build script actions to be version aware (or version controlled), so I can always get back to any version of the source and my build actions will be relevant to that version.
Of these tools, my two favorites are FinalBuilder for build scripts and TeamCity for CIservers. If I weren’t able to use FinalBuilder (which is Windows only), I’d use Rake, because I despise the use of XMLfor build management. It makes the build scripts very hard to maintain. Rake is XMLfree, whereas MSBuild or NAnt will force so much XMLdown your throat you’ll be dreaming of XMLtags in your sleep for a few months. Each tool on these lists excels at doing one thing really well, though TeamCity has been trying to add more and more built-in tasks, which I think drives people to create less-maintainable builds
Triggering builds and integration
We briefly discussed CIbefore, but let’s do it a bit more officially. The term continuous integrationis literally about making the automated build and integration process run continuously. You could have a certain build script run every time someone checks in source code to the system, or every 45 minutes, or when another build script has finished running, for example.
A CIserver’s main jobs are these:
- Trigger a build script based on specific events
- Provide build script context and data such as version, source code, and artifacts from other builds, build script parameters, and so on
- Provide an overview of build history and metrics
- Provide the current status of all the active and inactive builds
First, let’s investigate triggers. A trigger can start a build script automatically when certain events occur, such as source control updates, time passing, or another build configuration failing or succeeding. You can configure multiple triggers to start a specific unit of work in the CIserver. These units of work are often called build configurations.
A build configuration will have commands that it executes, such as executing a command line, compiling, and so on. I would advise limiting those to an executable, which runs a build script, kept in source control, to maximize action compatibility with the current source version. For example, in TeamCity, when creating a build configuration, you can then add build steps to that configuration. A build step can be of
several kinds. Running a DOScommand line is one of those types. Another might be to compile a .NET.sln file. I stick with a simple command-line build step, and in that command line I execute a batch file or a build script that’s in the checkout source code on the build agent.
A build configuration can have context. This can include many things, but usually it includes a current snapshot of the source code from source control. It might also include setting up environment variables that the build script uses or direct parameters via the command line. A context can also include copying artifacts from previous or different build configurations. Artifacts are the end results of running a build script. They could be binary files, configuration files, or any type of file.
A build configuration can have history. You can see when it ran, how long it took, and the last time it passed. You might also see how many tests were run and which tests failed. The details of the history depend on the CIserver.