Tuesday, November 06, 2007

xUnit, schmUnit (p&p, day 2)

Unit testing --> "programmer testing"

Not about TDD, though TDD is a good (the best?) way to do unit testing

"I understood too much about how the system is supposed to work to test it effectively. But if I do the test first...," no preconceptions about how system works.

Non-functional requirements: the "-ilities" (some, like usability, I've previously called qualitative; others are more technical, like scalability, maintainability)

Lesson 1: just do it; there are good reasons, pros, cons, whatever, just do it

Lesson 2: write tests using the 3A Pattern
  • Arrange: set up the test harness (instantiate the objects, fill in pseudovalues, etc.; the other stuff you can't test without)
  • Act: do the thing (the one whose workingness you want to test)
  • Assert: verify the results (test one thing per test, regardless of how many Asserts are needed)
Lesson 3: keep tests close to production code; don't make private stuff public just to make it testable to an artificial test architecture (e.g., separate assembly)

Lesson 4: use alternatives to ExpectedException
  • it violates 3A (NUnit syntax places the test out of order)... use Assert.Throws() with delegate{} (imperfect, but better) or .NET 3.5 lambda thingies
  • not always enough info about where the exception threw from, or should have thrown from, in processing order
  • Assert.Throws() returns the exception itself for further inspection
Lesson 5: small fixtures; separate fixtures for all the tests associated with a particular method, setups will be similar

Lesson 6: don't use SetUp and TearDown, even at the expense of some code repetition in tests; although small fixtures should help with this, they won't always

Lesson 7: improve testability with Inversion of Control (a pattern; Dependency Injection Frameworks use this but are themselves overkill for "most" applications)
  • constructor injection
  • setter injection (create an interface for the thing that needs to be mocked in the test; swap out the set method for test purposes)
  • cascading failures are unhelpful; isolate the code such that if change one part of code, one test should fail, and the failure should point you to the actual place where the problem is
Lesson 8: doesn't like mock object frameworks; they violate 3A

Just seeing these examples is one more step toward "contextualizing" this stuff for me. Cool.

No comments: