loading...

Test Contravariance - Who Understands It And Can Provide an Example?

scotthannen profile image Scott Hannen ・2 min read

I deal with brittle unit tests that I have to fix every time I change production code. I don't just deal with them, I write them as fast as I write production code.

To me this is far better than not having or writing unit tests. I still get many benefits, which include that writing unit tests guides towards writing cleaner, simpler code.

But there's another level I haven't gotten to yet, and I want to get there. Robert Martin's blog post Test Contra-variance provides the outline of something better, but I have no idea what the reality looks like.

Most of the time I create test classes that directly correspond to the classes they test. Breaking away from that seems like a first step, even if it's not technically any different, just because it breaks the habit. Instead of writing a FooTests class to go with my Foo, I write a FooDoesX class with tests for that particular behavior.

That's surface-level, though. Under the hood it's essentially the same old test class. I can make it a little less brittle by reusing some setup, with the goal of minimizing code duplication within tests while still ensuring that the "arrange" for each test is explicit so that it's clear what behavior it's testing.

Can anyone provide an example, perhaps in a public repository, of test contravariance? I'm not looking for a general discussion of unit tests vs. integration tests or testing a single class vs. testing a class with its collaborators, although there's likely significant overlap. I'm trying to see if someone who understands exactly what Uncle Bob is talking about can elaborate or provide an example.

Thanks!

Posted on by:

scotthannen profile

Scott Hannen

@scotthannen

I’ve been developing software full time since 2003, beginning with languages I’m still embarrassed to mention.

Discussion

markdown guide
 

What I understand is that you should design your tests to be another client for your code... so if in your production code you have an explicit API to use for your client... you should also use that API for your tests...

I prepared an small example with the TicTacToe game. You can find it on gist.github.com/bhserna/882d5101bd......

In particular look how I used the internal class Game::Board but I don't have a test for that class, because its behavior is already covered in the tests for the game.

This is a small example, but I hope you can find it useful =)

 

Hi,

I appreciate the example, but could you just link to the source code instead of posting it? It's about seven pages of scrolling and I'm concerned that it might stifle additional responses.

Thanks!

 

Ready! I just remove the code from the post... It would be nice to see an example from you also =)

Thanks! I don't have one. I'm going to go back and read Robert Martin's post all over again.

 

You might check this article here: medium.com/@tacsiazuma/the-lost-be...

It focuses on refactoring, but test contra-variance also applied to do it.

 

Thanks. That does touch on it. What I'd really like, though, is to be beat over the head with it, without a trace of subtlety, and without diluting it by incorporating any other concepts.

When I was getting started (and even now) a big problem was that an article would explain something but make the context so complex that it was difficult to isolate the part I wanted so that I could apply it in another context.

Over time I've gotten better at seeing through that, but I'm still just as likely to just skip to the next article.

 

Maybe this can answer your questions: github.com/FagnerMartinsBrack/nsa-.... See the test files.