Sign up ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

This question already has an answer here:

While practicing TDD, I came across this specification:

A user should be created with its password hashed, be persisted and an activation token should be returned.

Should my first unit test, (aiming to begin to test this scenario) should encompass the whole needs? :


Or rather, splitting its main parts into several smaller tests, and testing incrementally:


To put in a nutshell, should I rework the same test until a whole scenario passes? Or should I proceed incrementally by specifying additional features in other small tests.

IMHO, the benefit of the first solution is that the spec is defining in one place, no need to gather some chuncks of features to figure out the whole. On the other hand, the number of assertions and expectations might be huge, therefore the test code would be less readable.

share|improve this question

marked as duplicate by gnat, MichaelT, Kilian Foth, GlenH7, Yusubov Jul 24 '13 at 17:43

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

@gnat Very instructive, thanks :) – Mik378 Jul 23 '13 at 15:11

1 Answer 1

up vote 9 down vote accepted

tl;dr: Second option. You should split into several smaller tests, as that is what you're supposed to do with TDD (Red-Green-Refactor).

You start writing the simplest tests first to start out with the simplest implementation and build your way up towards a full scenario. The semantics with unit tests is totally different with scenario/functional/acceptance testing. Developers tend to confuse them all as the same but they're semantically different and fill different purposes.

TDD is built on the concept where a test has the granularity of a unit. Usually this unit is down to a method in a class. The whole point with TDD is to design code to be testable. If you start with a whole scenario as a unit and not the actual methods themselves you'll end up with code that may be doing too much.

There are different ways to go about with your scenario. I would roughly start by trying the following:

  1. First write a UserService that can create a new user with a single test createUserShouldReturnUser.
  2. Then write a IActivationTokenFactory interface that creates activation tokens. On UserService I'd continue with a test that uses the token factory as a mock object. The test is createUserShouldRequestActivationToken that requests any activation token from the mock object and puts it on the user object that is returned.
  3. I proceed to write a concrete ActivationTokenFactory that implements IActivationTokenFactory. The test is to make sure it produces "legit" tokens.
  4. and so on... I can imagine some kind of HashFactory object and some kind of persistance layer would be created as well.

Rinse, repeat until I have a full scenario and refactor along the way. I'd write the scenario test by now that exercises all the code, and make sure I have some unhappy paths to test as well (with failed persistance exceptions and whatnot).

It's easier to implement something if you divide and conquer... which is what you're supposed to do with TDD. Once you hit a snag, it's good to have these tiny unit tests for regressions if you decide to refactor something.

share|improve this answer
Thus the second suggestion (with several small and cohesive tests) would better fit to TDD, wouldn't it? – Mik378 Jul 23 '13 at 12:47
Awesome answer :) So, your last (and full scenario) would look like: shouldPersistTheNewlyCreatedUserWithAHasedPasswordAndReturnACorrespondingActiva‌​tionToken with all mocks expectations (gathering the ones from the previous cohesive tests)? The difference being that I ended up with a code designed by my first cohesive tests :) Thanks a lot! – Mik378 Jul 23 '13 at 12:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.