I recently gave a talk (in Spanish) about TDD with ASP.NET MVC. You can view the video here. I took baby steps to write the code, using the TDD “write the test, red, green, refactoring” cycle. I have other similar examples, in my posts and in my github account. Usually, I don’t write mocks nor stubs. I could be classified as a “classic” TDDer, in contrast with the “mockist” school. My reference for this dichotomy is Martin Fowler’s article:
That is: I add a mock ONLY if really, really need one. But someone could say: “Ah! Then I use mocks in every tests”. I don’t think so: mocks are not an imperative in TDD programming. My purpose is to show the fallacy of such assertion. You can decide to use or not to use mocks/stubs. Mocks are only REALLY needed in certain circunstance in TDD (another story is the need of mocks in testing out of TDD, maybe in “test-last only for code coverage” cases).
I read in that article:
xUnit tests follow a typical four phase sequence: setup, exercise, verify, teardown. In this case the setup phase is done partly in the setUp method (setting up the warehouse) and partly in the test method (setting up the order). The call to
order.fillis the exercise phase. This is where the object is prodded to do the thing that we want to test. The assert statements are then the verification stage, checking to see if the exercised method carried out its task correctly. In this case there’s no explicit teardown phase, the garbage collector does this for us implicitly.
Yes, I usually write the test with an “arrange” part, that setup the scenario. The mockist school use mocks for that (see the other example in Fowler’s article). In that article you can see that we can use OR NOT a mock to test a feature. Fowler writes:
The classical TDD style is to use real objects if possible and a double if it’s awkward to use the real thing. So a classical TDDer would use a real warehouse and a double for the mail service. The kind of double doesn’t really matter that much.
A mockist TDD practitioner, however, will always use a mock for any object with interesting behavior. In this case for both the warehouse and the mail service.
All this topic is related with what we call a Unit Test. It’s not a clear term: many books and articles mention it BUT without a clear definition. So, I read in the wikipedia:
In computer programming, 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. Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming a unit could be an entire module but is more commonly an individual function or procedure. In object-oriented programming a unit is often an entire interface, such as a class, but could be an individual method.  Unit tests are created by programmers or occasionally by white box testersduring the development process.
The key part is: a Unit Test exercise a part, usually, an individual method. In the act part, (remember: Arrange, Act, Assert), I write only one statement: the call to the method I’m testing, nothing more, nothing less.
BUT MANY PEOPLE think: that call should only traverse that method, not other involved parts that method calls. Well, that is not an imperative in TDD. The first example in Martin Fowler’s article uses another instances in the setup/arrange part. And those instances are real production code, not mocks nor stubs. That is the “classic” school in TDD.
I read in the Wikipedia article:
The key part is “ideally”. Ideally for what? For testing in isolation. But all solutions have their pros and cons. IMNSHO pursuing isolation should be evaluated in terms of cost vs benefits. My conclusion, in my experience: it doesn’t pay to use mocks. They are add a lot of code, mainly only to get isolated test. Instead, I use real production code in context. Fowler mentions Object Mother:
In practice, classic testers tend to reuse complex fixtures as much as possible. In the simplest way you do this by putting fixture setup code into the xUnit setup method. More complicated fixtures need to be used by several test classes, so in this case you create special fixture generation classes. I usually call these Object Mothers, based on a naming convention used on an early ThoughtWorks XP project. Using mothers is essential in larger classic testing, but the mothers are additional code that need to be maintained and any changes to the mothers can have significant ripple effects through the tests. There also may be a performance cost in setting up the fixture – although I haven’t heard this to be a serious problem when done properly. Most fixture objects are cheap to create, those that aren’t are usually doubled.
In my video example, I use something similar to an object mother that prepares the scenario, loading the domain from JSON objects. That object mother only appears when I needed. TDD favorites the use of YAGNI: don’t add something if you don’t need it yet. In many projects I ended using an in-memory domain, with an in-memory database. Read In memory database by Fowler. An example of my code and its evolution (many atomic commits): https://github.com/ajlopez/TddOnTheRocks/tree/master/TddApp. And in that example, I started by the controller (top-down). You can write TDD top-down or bottom-up, with AND WITHOUT mocks. The use of mocks is not related to the direction of code. A very interesting reference about deferring database and implementation details is @unclebobmartin article: No DB:
The center of your application is not the database. Nor is it one or more of the frameworks you may be using. The center of your application are the use cases of your application.
What is the best time to determine your data model? When you know what the data entities are, how they are related, and how they are used. When do you know that? When you’ve gotten all the use cases and business rules written and tested. By that time you will have identified all the queries, all the relationships, all the data elements, and you’ll be able to construct a data model that fits nicely into a database.
Does this change if you are using a NoSql database? Of course not! You still focus on getting the use cases working and tested before you even think about the database; no matter what kind of database it ends up being.
I was able to follow that way, without writing any mock.
What about the lost of isolation? In my projects and experience, it was not a problem. If you broke something “big”, maybe you will have 40 tests in red, but a quick inspection will reveal that 15 are in controllers, 20 in service layer and domain, and 5 in a repository. Then, the problem is highly related with the repository. Isolation is not needed, if your code is written with TDD.
Recently, I worked in a team, with people with different styles. Someones doesn’t use TDD, only “test for code coverage”, and TDDers were from both schools: classicals and mockists. Then, when someone should refactor an implementation, the classic tests were still in green. The mockist tests usually went red: the mock preparation and assertion were SO TIGHLY ASSOCIATED to internal/current implementation, that refactoring was a pain.
When to use mocks or even an stub? Well, that decision is up to you. I only want to show that is a decision in context, not a direct no-brain decision. Really, it’s rare the occasion I use a mock. I prefer to write code for production, not for test support. An example: if I have a code that I don’t write, maybe a web service to consume, I wrote not a stub, but real production code to use in the iteration outcome, instead of calling the exterior web service. I wrote an spike or some tiny apps to exercise, test the exterior code, meanwhile, my end customer/product owner see the advance without using the exterior code, yet, with all the disclaimer associated with that situation. In this way, my code is lighter, and I can embrace change easily.
A need for mocks? Maybe, in a distributed team. Team A could write the controllers, Team B could write the service layer, but Team A at some point need consume the still under-construction services, so they resort to write mocks/stubs. That is, IMO, a real case for mocks.
Comments? Another pros/cons of classic/mockist approaches?
More TDD articles are coming.