-
Notifications
You must be signed in to change notification settings - Fork 13
Testing, Testing, 1 2 3
For those of you who know about code testing, you will soon see that the three main project categories in Tripod follow a pattern when it comes to your test projects. For those of you who don't know about code testing, or at least what my perspective on it is, there are three broad categories of software tests:
-
Unit Tests
Unfortunately I hear this term misused way to often, and I wish I knew why. Recently a developer with a customer company told me that we should have unit tested certain application features. I also hear developers say all the time that they still need to "perform" some unit testing, and it drives me mad. Why? Because you don't "perform" unit tests - a machine does. And you don't unit test application features, you unit test the smallest units of code in your application: Methods. (Note that in this context a "Method" can be an object constructor, property setter / accessor, or another code artifact with some kind of executable body.) <br/ >
A unit test is a piece of code which will invoke a method (or constructor, or some other operation) on another piece of code and checks the results against hard-coded expectations. Unit tests result in either a pass or fail, are your first line of defense against bugs, and should execute fast. Unit tests should also only test your solution's source code, and should not need any external systems like databases, email servers, etc. in order to be able to execute the method under test. That said, testing how your source code plays with external systems like databases and mail servers can be valuable, and these kinds of tests are not difficult to write or automate. However tests that actually reach outside of your source code and send / receive data to / from other systems are not unit tests, they are... <br/ >
-
Integration tests
Integration tests usually take a little longer to execute than unit tests because they will actually reach outside of your source code and interact with external systems -- like databases, mail servers, the filesystem, possibly even the web. You can even have both unit tests and integration tests for the same method. The difference is that a unit test will mock the external service with a tool that pretends it is the external system, whereas an integration test will actually connect to the external system. However, like unit tests, integration tests should not need to fire up the full application in order to execute and deliver a pass or fail result. <br/ >
-
User acceptance tests (or end-to-end tests)
Both Unit and Integration tests execute without any kind of user interface or other mechanism with which to receive events or inputs from a user. If you are writing an MVC application, chances are your users are going to be using a web browser like Chrome or Firefox (hopefully not Internet Explorer). You could have hundreds of unit and integration tests for your awesome use case, but if some<button>
has a bug in itsclick
handler, a user won't be able to do shit with it. When a browser is fired up, navigated to a URL, and observed or acted upon in some way to achieve an expected result, this is my definition of a User Acceptance Test (UAT). <br/ >
Unlike unit and integration tests, UAT's can be run by an end user. They can also be automated with tools like WebDriver, WatiN and the like, but either way, these tests run much more slowly than integration and unit tests. They are also much more expensive, and serve as the last line of defense against errors in your code. Many times when a bug is discovered during a user acceptance test, you can write one or more failing unit or integration tests to demonstrate the bug. After you fix the bug, those tests, along with the UAT, should pass.
##Tripod's Testing Pyramid
Remember that pattern I mentioned at the top of this page? Let's revisit the 3 main assembly categories in Tripod:
-
Domain assembly
You should never write integration tests for your domain project, and you cannot write UAT's for it. Remember the domain assembly does not depend on the services assembly, Tripod inverts that dependency. All of your code for connecting to external systems is in the services assembly. So the domain project(s) should only have unit tests. <br/ >
-
Services assembly
The services assembly can have both unit tests and integration tests, but still cannot have any UAT's. Remember the services assembly contains your implementations of interfaces that will connect to lower level systems. Since that code resides here, this is the place to test how well your solution's code integrates with those other systems. You can also have unit tests for any code in this assembly that does not need to connect to external systems. <br/ >
-
Application assembly
This assembly can have all 3 -- unit tests, integration tests, and user acceptance tests. Because this application is the entry point for your user, it is the only place where you can have UAT's. You should also have unit tests for the application project(s), and possibly integration tests if needed. However in practice, most of your integration tests should be against the services project. <br/ >
I'm sure I'll receive emails from people saying there are other types of testing -- load testing, regression testing, usability testing, etc. From my perspective, most of them ultimately boil down into one of the categories mentioned above. The point I am trying to drive home is that each of these testing categories correlate with the three project categories in a Tripod solution architecture. It forms a sort of pyramid, where your application can have all three test project types, your services can only have integration and unit tests, and the domain can only have unit tests.