I Just Got Test Infected! An IM with Liz Keogh
I'd spoken to a number of different developers, but I really hadn't got much input on the details of naming and structuring of tests. Pragmatic JUnit had some thoughts, but to be honest I didn't love the naming used in most of the books. The most interesting information I found online was Dan North's intro to BDD which mentioned that test names should be sentences and that "should" in the test name helps to keep the tests focused on the behavior of the class under test. I looked at the tests within some OSS projects but hadn't really had an "aha" moment. However, I was lucky enough to catch up with Liz Keogh over IM and in a few minutes I really started to get a sense of how she approached naming tests. Here's a summary of the IM conversation:
PB: Hi Liz, Any great references you've found on naming/structuring unit tests that are complimentary to the BDD stuff?
EK: Um, only the BDD stuff I'm afraid You can try looking at Dan's article on it... http://dannorth.net/introducing-bdd
PB: OK, thanks. I've been all over the BDD stuff and Dans article. Was just wondering if there were any other perls of wisdom!
PB: Out of interest do you actually put the word "should" into most of your test names or do you just use that concept to make sure all of the names are focusing on a description of a desired behavior?
EK: Always use should
EK: It helps me remember that I can question the behaviour of the thing I'm looking at
PB: So testCreateBaseObject becomes testShouldCreateBaseObject?
EK: Sure, if the thing in question should create a base object
EK: When should it create a base object?
PB: That test is just confirming the class file exists and you can construct it without it failing
EK: shouldBeConstructableWithoutFailingWhenClassFileExists?
PB: testGetNonExistancePropertyThrowsError becomes testShouldThrowErrorWhenGetNonExistantProperty?
EK: Make it a sentence
EK: My class should throw an error when I try to get a non-existant property
EK: -> shouldThrowAnErrorWhenITryToGetANonExistantProperty
PB: Wow - no shortening at all?!
EK: Why would you? Does it make it more readable?
PB: Nope
PB: And I read more often than write
PB: And can type fast - right?!
EK: Yep
PB: Makes perfect sense
EK: So, I don't shorten stuff EK: It also says who's going to use it that way - "I" usually means "the calling code"
EK: But it's comprehensible. Also I like anthropomorphizing my classes - it helps me think of them in terms of customers, behaviour, interaction, responsibilities
EK: So, when you described the test to me and what the class should do
EK: your description was different to the test name.
EK: Rename the test.
PB: LOL!
EK: Other than that - Given / When / Then applies at a unit level too
EK: I don't always use it, but often if a test is complex you'll see me put
EK: // Given
EK: (set up contexts and stub mocks)
EK: // When
EK: (perform events)
EK: // Then
EK: (assertions, verifications, etc.)
PB: Cool!
EK: Do you usually have 1 test class per class for unit tests or is it more behaviorally grouped?
EK: Behaviourally grouped
EK: So, I put enough examples in to describe one aspect of behaviour in each test
PB: If you looked across a code base what might be ratio of test classes to classes?
PB: 3:1?
EK: Hm, 1-to-1 normally, except maybe for really simple data structures
EK: and even those often have an equals method - I always cover that with a description
EK: Maybe I don't always have behaviour for GUI classes
PB: OK, what about a class that has more than one type of behavior though?
EK: Why do you have a class with more than one type of behaviour?
PB: Good point!
EK: *smiley*
EK: There are also system-level behaviours; I guess that depends how complex the system as a whole is, and how much certainty you want over its behavior
EK: I usually have about 10 scenarios for the Game of Life
PB: Test class naming just a simple test
PB: The scenarios would be separate functional tests?
EK: If you're doing strict BDD, you'll be starting from the user interface
PB: What about writing frameworks?
PB: Are there any OSS projects that use the should test naming convention or that you'd otherwise recommend checking out the test code as samples of good/best practices?
I really found it hugely valuable to get input from Liz who's clearly got a lot of experience with (B/T)DD. Now I just need to go write some tests and see what I run into. Many thanks Liz!
PB: Right - not worrying about functional or acceptance testing yet
EK: I'm using JUnit 4.4 now, so I'm calling them XYZBehaviour - you don't need to call anything Test any more, except for the @Test annotation
EK: But if that's the convention where you are I wouldn't buck it
PB: I'm the only programmer so the standard is whatever I do today :->
EK: Heh, a nice place to be!
EK: Yes, separate tests for the whole system
EK: The kind of thing QAs might script up
EK: Work out how that behaves - that gives you the scenarios for that bit of the system
EK: A library?
PB: Lets say you were coding an ORM? You'd create a specific project as a scenario for testing?
EK: Drive it using examples, IMHO - it's working really well for JBehave2
EK: Take an example of whatever might use the library
EK: So, yes... think of a suitable customer for your library, work out what the ideal way of using the library would be from the customer's point of view
EK: It's very RSpec-like
EK: (Your customer can be another piece of code, or a user, or another system or application)
PB: Ah, ok, that'd make more sense for some of the library stuff
EK: So treat the API as the UI?
EK: So, for JBehave 2 I coded up the game of life, wrote the first scenario and said "That's how I want JBehave to work"
EK: I wrote the scenario file, the definitions of the steps, etc.
EK: Then wrote JBehave2 to make it work
EK: Without compromising the user interface
EK: Otherwise you're giving people what you think they want, instead of responding to what they actually want
EK: If you can find real people who want to use your library, that'd be even better
PB: Ahhh
PB: Makes sense. Otherwise you end up with an API that doesn't work for real scenarios
EK: Exactly
EK: Make it work for something simple, get it out there and get feedback, then add on the handling for exceptional cases
PB: And presumably you write the simplest API that'll meet the scenarios and then if you want a richer API, evolve it by adding scenarios requiring a more complex API
EK: Yes
EK: It's possible to spot things that might be useful to configure
EK: For instance, we parse arguments with a string that looks like "Given a cell at ($row, $column)"
EK: But I'm going to inject the parser into the framework
EK: So that if anyone wants to code a parser that works with, say, %row, %column, it will
EK: So, if someone wants to have XML definitions of scenarios, or do something else that's complicated, they can define how it's done themselves
PB: Nice
EK: I'm not providing them with tools to do that, though, just the ability to create those tools themselves
PB: Any language
PB: Ideally something in an xUnit format
EK: Hm, there must be a few RSpec samples
EK: Try Mockito; that's Szczepan's mocking framework
EK: He drove that using BDD
EK: I think he used JUnit for it
PB: Checking it out from svn now - tnx!
PB: Mockito - we have liftoff - shouldRemoveStubbableFromProgressAfterStubbing(), etc. Perfect
EK: There are tons of enterprise projects - non-OSS - that use the shouldDoSomething naming - it works
EK: Anyway, good luck Let me know how it works out for you!
PB: I figured if you, Dan et al were doing it, it was probably a pretty good idea!
PB: Thanks a lot


