Friday, January 18, 2013

Good practises for unit testing

When performing unit test (no matter which language, the same applies to e.g. javascript unit tests) make sure your tests are fullfilling the some quality criteria.

Unit tests should...

... be deterministic: Assert.Equals(Random.Next(), myResultingNumber) is probably a bad idea ;-)

... be repeatable: you should be able to run them 1, 100 or 1000 times in a row, the results shall always be the same.

... be order independent: running TestB before TestA shouldn't have any influence.

... be isolated: strive for not using external systems like databases or services, use a mocking framework instead. Reason: doing not so will make it hard to fulfill some of the other principles listed here, e.g. "fast", "easy to setup", "deterministic" (think about a temporary network problem when connecting a test database).

... run fast: slow tests will decrease your productivity and they will be run fewer times because no one likes waiting

... be included in continuous integration process: don't rely on developers manually triggering of the tests, they should be run automatically (as often as possible).

... be easy to setup: the danger in hard to setup tests is that they are simply not written.

... be either atomic or integration tests: atomic tests (i.e. tests that cover a very specific, small amount of functionality) are a must, integration tests (covering the collaboration of multiple modules) are not always necessary but sometimes useful. The disadvantage in integration test is that in case of failing tests, problems are harder to find whereas a failing atomic unit test often even does not have to get debugged to find the problem. Do not mix both types but make a clear separation (e.g. by introducing naming conventions).

... have one logical assert per test: does not mean you should never have multiple asserts in your test case, but if this is the case make sure the asserts are tightly logically connected to each other.

... concentrate on the public "API" of your SUT (which normally covers private methods. Note that the need of testing private methods is often an indicator for violation of SRP within the class).

... read like documentation for your system: benefit from your test suite also in a way that it is an additional documentation for your software. Actually, a system without unit tests cannot be conidered as being "valid": it might be free from obvious bugs (such as users get error messages), but that does not always mean that it works as it should (and often other documentation - if available at all - is far away from being as precise as unit tests in describing desired behavior).

... have the same code quality as productive code: there is NO reason for neglecting unit test code. It will grow like productive code grows, you will get the same problems as with your productive code if you are not applying the same patterns and practises.

... also cover the "sad" path, not only the "happy" path: also test unexpected values and behavior including tests for exceptions.

... be written each time a bug in development, testing or on your live system is occuring. Like this you make sure that this bug is abandoned forever.

No comments:

Post a Comment