1. Intro to unit testing
Steven Casey
twitter.com/stevencasey
2. An intro to a test of a unit
Obligatory wikipedia quote: “unit testing is a
method by which individual units of source code,
sets of one or more computer program modules
together with associated control data, usage
procedures, and operating procedures, are
tested to determine if they are fit for use”
(emphasis mine)
http://en.wikipedia.org/wiki/Unit_testing
3. What to test
everything? nothing? what I feel like?
Its a tough decision to decide where to draw the
line between the obvious safety net of unit tests
and the cost of writing & maintaining those unit
tests.
4. • Lots of tests, will cost more to maintain over
time and always have the potential to create
almost as many problems as they solve.
• BUT…
• A lack of tests, doesn’t give you confidence to
work with the glorious safety net that really
good test coverage provides.
• and, more importantly, quality assurance &
rapid feedback
5. Tightrope?
• Absolutely. One that requires discipline. Tests
should be first-class code citizens.
• Otherwise they can become useless, ignored,
a dead pool of code that no-one wants to
maintain. Then you have a new kind of legacy
codebase… sad face
6. So, what to test?
Use the force? Guess?
Or, you can rely on a mix of complexity analysis (get yer
cyclomatic complexity analysis ON), branches & iterations are
candidates here
Maybe, also considering edge-cases/boundary conditions for
core business functions (xunit/mbunit for iterative testing
rocks!)
Or, if you have a legacy codebase. What are the hot classes
always changing? Wouldn’t it be nice if you could wrap those
in tests and optimize that code with confidence!
7. What not to test?
What doesn’t add value?
- Code that never changes (or least likely to…)
AND isn’t broken (yet)
- Code that cannot be mocked/faked. EG calling
an API.
- Non-public code! Only test the public
interface of your class under test, not the
internal implementation.
8. What not to test
• Globals, statics, persistent data (DB, IO),
distributed data (memcache)
• You will quickly find yourself thinking, how can I
test this and (hopefully) deciding to avoid globals
& statics as much as possible.
• Does your test connect to a shared db? Ok, stop!
You cannot guarantee a repeatable isolated test
there can you? Stay tuned for details on
mocks/fakes/stubs!
9. How to structure a test?
Arrange Act Assert: a sample…
[TestMethod]
public void RegisterWithValidInputs_SendsEmailForVerification()
{
// Arrange
var register = _sut.RegisterNotifications;
// Act
var result = _sut.Index(new RegisterUserViewModel(){ Password = "password",
Email = "john@smith.com", FirstName = "john", LastName = "smith“ })
as ViewResult;
// Assert
register.ReceivedWithAnyArgs().SendUserActivationActionEmail(null);
}
10. RR Record-Replay
• Record-Replay: for me, mind bending. I much
prefer AAA and just about every OSS project I
see does too. So, I will not cover it here.
• For more, read:
http://ayende.com/wiki/Rhino+Mocks+Record
-playback+Syntax.ashx
11. Test structure, syntax
• Follow a naming convention for tests.
• A Suggestion is that you first name the method
you are testing, the inputs, and the expected
result. Be descriptive over shorthand, these
descriptions will help identify quickly what test is
failing when you have several hundred (or
thousand) tests.
• Alternative conventions exist:
– GivenWhenThen syntax (my favourite approach for
BDD-style tests)
12. Test Setup
Avoid IOC. Testing your code is easier without
registration logic.
Use a mocking framework only for non-trivial
dependencies. I recommend Nsubstitute!
The testing framework usually has 2 types. One for
class level and one method level which runs
before/after every test.
Use the method setup and teardown methods for
creating and destroying the system(class) under
test, to ensure a clean SUT for each test & keep the
repetitive code out of your tests.
13. Some tips on writing tests…
• Change code first, then tests. If u change both
at once, well, how do u know which is broken!
• Test’s should be independent of one another
• Test one thing (behaviour) per test. (yes, its ok
to have multiple asserts, as long as they all
test the same behaviour)
• No conditional logic, no loops, no exception
catching (unless its an expected exception)
• No test logic in production code
14. more tips…
• Don’t create methods/props in production
code only for use by tests (can you smell the
bad design?)
• 1 test class = 1 class under test (don’t mix the
classes you are testing, it gets confusing
quickly!)
15. Mocks, fakes, stubs, huh?
• Stub: replaces implementation with code that returns a
specific result. No asserts on stub.
• Mock: all about asserting that something has been called,
perhaps with particular params
• Fake: anything that is not a ‘real’ implementation. You may
create a fake to validate behaviours of SUT or to return
specific results.
• http://www.martinfowler.com/articles/mocksArentStubs.ht
ml
16. A test of sorts…
So finally, all your tests pass, w00t! But, someone
finds a bug. What should your next steps be?
If you said/thought…
write a test to repro the bug and then fix the test.
Well sir (or madam) , I think you got it!
17. Fin
Initially written & presented 2010 @ communityengine. later adapted
& posted for posterity here to have a nice reference for hopefully
encouraging others to improve their approach to testing.
Steven Casey. twitter.com/stevencasey. feedback encouraged!
References:
• http://blog.stevensanderson.com/2009/08/24/writing-great-unit-
tests-best-and-worst-practises/
• http://www.slideshare.net/nickokiss/unit-testing-best-practices
• Art of Unit Testing by Roy Osherove (read it!)