Writing Unit Tests
Why do we write unit tests?
Improve code quality
Fewer reported defects
Make checking code faster
Tell us when we've broken something
Tell us when our work is done
Allow others to check our code
Encourage modular design
Keep behaviour constant during refactoring Functions as a spec (think TDD)
The law of diminishing returns most definitely applies here
Testing everything is infeasible. Don't be unrealistic.
70% code coverage is actually pretty decent for most codebases.
First, test the common stuff.
Next, test the common exception-case stuff.
Then test the critical stuff.
Add other tests as appropriate.
When to write a unit test
Use a unit test to provide a framework for writing your code
If you find yourself running up an entire application more than once or twice to test a particular
method you've written, wrap it in a unit test and use that test to invoke it directly
^R ^T is your friend
When someone comes to you with a bug report, write a test to reproduce the bug.
Key Principles for Unit Tests
Each and every test must be able to be run in isolation
Tests should the environment up for themselves and clean up afterwards
- Use your ClassInitialize, ClassCleanup, TestInitialize and TestCleanup attributes if you're in MSTest-land, and the equivalents for NUnit, XUnit etc.
Tests should never rely on being executed in any particular order (that's part of the meaning of "unit")
Tests should not rely overmuch on their environment
Don't depend on files' being anywhere
Don't hard-code paths. This will bite you.
If a class depends on another class that depends on another class that you can't easily instantiate in your unit test, this suggests that your classes need refactoring. Writing tests should be easy. If your classes make it hard, fix your classes first.
Tests should be cheap to write
Don't worry about exception-handling - if an unexpected exception is thrown, the test fails. Don't bother catching it and manually asserting failure.
Be as explicit as you can
Don't allow for variations in your output unless you absolutely have to.
If there are going to be different outputs, ideally there should be different tests
Tests should be numerous and cheap to maintain
Each test should test one (perhaps two or three, but generally just one) behaviour
It's much better to have lots of small tests that check individual functionality rather than fewer, complex tests that test many things.
When a test breaks, we want to know exactly where the problem is, not just that there's a problem somewhere in a call stack seven classes deep.
Tests should be disposable
When the code it tests is gone, the test should be dropped on the floor.
If it's a simple, obvious test, it will be simple and obvious to identify when this should happen.
Tests need not be efficient
These allow you to call private methods and access private variables from another class
This deliberately breaks OO principles
Use it for testing implementation-specific stuff, but depend on concrete types when you do.
ASPX page testing
You can automate all sorts of stuff with respect to ASPX pages
This does not replace regression test automation (e.g. Selenium, Mercury et al), but should be used by individual developers when writing new ASPX pages and ASCX controls.
Don't run the application and click stuff manually
Write a unit test and tell it to click stuff automatically
Testing web service methods
The MSTest framework will get confused if you try to actually invoke things via HTTP.
It's better to just call the web endpoints directly in-process.
Using the unit testing framework for integration testing
- Have a couple of common-case "unit" tests that actually represent an end-to-end use case of your application.
Note for young players: if you get an invalid cast exception such as...
Test method Test.Zap.CubeModel.DigitalSearchTreeTest.TestInsert threw exception: System.InvalidCastException: Unable to cast object of type 'Node`1[System.Char,System.Char]' to type 'Node`1[System.Char,System.Char]'..
...it may be that your type is a nested class or similar and does not have public visibility.