London school TDD books?

Background

Hey guys, recently I bought a book on TDD that I am reading. The books is really nice and has some really juicy things on architecture, but at the same time it has two main characterists I really don’t like:

  • Its for C# and Java like languages (object oriented)
  • It is from the Detroid / Chicago school of TDD (classissist)

To me this poses an interesting issue as:

  • I usually work with functional languages (or somewhat functional)
  • I adhere to the London school of TDD

Suggestions?

So I was wondering if anyone here knows any TDD books for functional languages in general or for the London school of TDD.

1 Like

Could you elaborate on the differences between Chicago school of TDD and London one? I am curious, as I am not aware of them.

There are a number of articles you can read out there, I personally like this one (I may be biased):

quick quote:

Many comparisons between the two schools of thinking can be summarized as “top-down” versus “bottom-up”. Where London-school TDD encourages programmers to use external constraints as a starting point (an API endpoint, an HTTP controller, etc.), Detroit-school TDD encourages programmers to first identify the core domain logic that exemplifies the work without concern for how it might be integrated elsewhere.

For completeness sake:

While I personally like the starting point of the Detroit school (your start with the Domain problem, not the externalities) I use the London school to design tests.

A very good video about London TDD in Elixir can be seen here:

3 Likes

I personally find that article heavily biased (to be clear I’m a classicist myself). A great treatment of the topic is IMO Fowler’s Mocks aren’t Stubs. It’s lengthy, and also somewhat biased, but I think that Fowler does a good job of trying to be as impartial as possible.

2 Likes

Hi :wave: ,

Probably you should try to give a look at Growing Object-Oriented Software, guided by Tests - Steve Freeman, Nat Pryce (aka GOOS). It is also mentioned in the video description, along with other resources and examples.

I see that book as the subsequent step for Test-Driven Development: by Example - Kent Beck.

The GOOS book will introduce you to the world of Test-Double, Mock Objects, how the End-to-End testing fit in the development life cycle of an application, the concept of roles discovery, how to improve the test readability and more advises on how to deal with complex test cases (such as asynchronous code and threads). Starting from the Chapter 3, the authors will drive you with a worked example, by building an auction system using all these techniques.

If you are interested on all these topics, I would recommend you to join the Software Crafters Community on Slack.

3 Likes

Why do you prefer the classicist approach? Is it because you believe that the London school’s tests have a poor resistance to refactoring and are therefore seen as brittle or do you have another reason?

I understand both points of view, but after years of dealing with classicist tests, I find it always hard to pin point regressions in complex systems, where the granularity given to me by the London school tests helps a lot with that. Yes, the tests are not as resistant to refactors, but it is a trade off I am willing to make for the sake of granularity.

I am actually unaware of the opinion of Martin Fowler here (I don’t know if he is a classicist or a mockist), but I am going to read the article. How would you classify him?


@joebew42 To quote the book I am actually reading:

The classical approach is also referred to as the Detroit and, sometimes, the classicist approach to unit testing. Probably the most canonical book on the classical school is the one by Kent Beck: Test-Driven Development: By Example (Addison-Wesley Professional, 2002).

The London style is sometimes referred to as mockist . Although the term mockist is widespread, people who adhere to this style of unit testing generally don’t like it, so I call it the London style throughout this book. The most prominent proponents of this approach are Steve Freeman and Nat Pryce. I recommend their book, Growing Object-Oriented Software, Guided by Tests (Addison-Wesley Professional, 2009), as a good source on this subject.

In your opinion, which approach do you rather use? (or maybe you don’t care and use both?)

I already had your recommendation (GOOS) in mind, but thanks for making it clear. What did you think of that book?

Because in my view the main purpose of tests is to check the expected behaviour of the program, and the most direct and clearest way to do this is to verify that the program returns expected outputs for the given inputs.

This is definitely a big and an important reason. After a few decades of programming I’m absolutely convinced that:

  1. The problem domain is going to change significantly over the course of the project
  2. Our initial understanding of the domain is going to be overly naive. It takes time for our understanding of the domain to properly grow in our minds.

Refactoring is a practice which helps us addressing these challenges, making it possible to shift the internals of the code to match our view of the world and the ever changing requirements. If refactoring is not practiced, the code will rot. Well, either that, or we were somehow able to get the design right in the initial attempt. The latter is IMO less likely to happen than winning a lottery, but even if we are such lucky, the design will likely be overly complex for a better part of the project’s lifetime (see Fowler’s Yagni and Is Design Dead?).

Therefore, any practice which significantly affects the ability to refactor is IMO a very questionable practice.

Classicist testing has some shortcomings, and I agree that isolated tests have some interesting advantages such as the ones you mention here.

That said, when I look at the pros together with the cons, I believe that isolated tests suffer from some significant issues:

  1. Tests are less clear
  2. They give us less confidence
  3. By making refactoring more difficult, isolated tests restrain the evolution of the code design, thus effectively nullifying one of their advertised benefits of assisting with better design.

I also recommend watching this excellent talk on the topic.

Fowler is a classicist, and admits as much in the article.

4 Likes

I agree very much with what @sasajuric said.

I don’t know where I read it (unfortunately) but I’ve heard someone else say these very important insights:

  • Tests that always pass are not useful.
  • Tests that always fail are not useful.
  • Tests are by necessity coupled with your code. This makes changing your code harder. Whether this is desirable depends very much on the situation (and where you are at in your project’s lifetime).

So I see testing very much as a spectrum of trade-offs:
No tests make it scary to change code because you might introduce regressions.
Too many tests make creating new/changing existing features take a lot longer.

Finding where you want to be in this spectrum, and what parts of your project should be considered ‘stable boundaries’ vs ‘internals that are subject to change’ is the important challenge.
You should probably spend more time deciding how to structure these boundaries than on building the tests themselves.

1 Like

Thank you for asking me this question. In general, I do not have a strong opinion on which of the approaches is better than others. The only advise I feel to give is to try to learn, practice and experiment as much as you can with all of them (better if you try to exercise on the same Code Kata, using different approaches, so that you will have more material to think about). All of them are worth learning.

The reason why I invite people to practice all of these approaches, is because all of them have PROs and CONs, and based on the context and the purpose of what you want to achieve, you can understand which approach will be the best to use. In my opinion, the context and the purpose, are the main players that dictate when an approach is better than another. There are times - for example - when you don’t need any of these (spikes, code you know will be thrown away in the next 30 minutes, trying out if the code you wrote can work, etc …).

Sometimes, when I want to learn something new about a Framework, or a Library (like ranch, or cowboy, or plug), I prefer the London School approach: It gives me an “immediate” feedback that things are working with a minimal walking skeleton (being able to spawn a server and handle requests), and the Test-Driven pace gives me the scope of the thing I want to explore and learn at that time, proceeding at small steps (e.x. how to handle a GET? How to handle a POST? How to get HEADERs? What happen if the route is not defined? What about the sessions? And so on…), and, last but not least, having a safety net (tests from the outside) that give me enough confidence when I will try my braves refactoring moves. This is just an example, the topic is so vast, that’s why there are entire books on that matter.

The more you learn, the more will be easy for you to find out your trade-offs.

From my side, I see testing as a design tool, that also act as mechanism to prove the code is working as expected.

I think that is a book worth reading.

I can recommend Pragmatic Test-Driven Development in C# and .NET: Write loosely coupled, documented, and high-quality code with DDD using familiar tools and libraries https://amzn.eu/d/3SdAmG7

Ah! My favourite topic! :slight_smile:
One of my favourite programmers on TDD

He has a lot of interesting talks on youtube.
Moreover see what Leslie Lamport has to say :slight_smile: Leslie Lamport: Thinking Above the Code - YouTube

2 Likes