piątek, 15 grudnia 2017

Unit Tests are fun

Unit Tests are something that helps us breathe. Save hours for QA's so that they can focus on validating solution against their deepest fetishes, crazy ideas and bussiness requirements. Without them testing any implementation begins with confirming that the super hacky programmer didn't screw up the fluently working scenarion that were implemented last time.

Some programmers don't know how to write tests, some don't like doing that. But there are people like Uncle Bob, who can take your breath away speaking about testing. They make you believe, they make you wish to have that sweet automatic coverage, so you can push your commits as soon as all tests are green. That gives courage and will to refactor. Unit Tests are (as for me) the ultimate mean for continuous improvement, and that is fun!

So what are those wet dreams about? Recently I came back to my my Movie Organizer project. I craved for ad free subtitle downloader that I can run from console, so having all the subsystems in place I decided to go for it. This won't be about implementation, but improvements. When the SubtitleDownloader and it's Unit Tests were ready I got back there to mess around a little. For the sake of this article I'll focus only on the last test that was verifying the outcome. It required quite a lot of setting up (making this more like an Integration Testing) and some test data on side.

SubtitleDownloaderTests.cs

Looks messy, doesnt't it? So what do we have here?

  • Test data
  • Test scenario(Fact)
  • Lots of nasty, Moq specific setup code
  • Even more of validation code
That's not exactly object oriented approach, even though all the methods are meaningful, they're just colorful packages full of nasty laziness.
So how we improve?

First thing I looked into was my SpyStream. It's only used by mock of IFileHelper to prevent it from failure while writing subtitle contents. That gave me the idea of breaking test class apart and instead of using Mock directly with generics, configuring it like it's object from outer space, I started building on top of it.
After happily deriving from Mock I realized that that's not the game I'm aiming for. Entire Mock's interface was exposed, leaving me with the mess I've had.
Next idea yielded something more interesting. FileHelperMock became an adapter.

FileHelperMock.cs

That separated me from vast amount of possibilities, that intellisense was flooding me with, every time I typed a dot after _fileHelperMock. This mock now contains only what's important for me to verify, encapsulates trivial setup and maintains life of the stream. It's not much in context of this single mock, but after refactoring all of them - there was some space for light to come through.
Below is how the Mock became bussiness related object

RpcClientMock.cs

Test class after this refactor.

SubtitleDownloaderTests.cs

Not bad. But still test scenario is polluted with all the responses and constant data. I also wanted to move out that Func that's responsible for verification of the outcome. For now I just extracted it all to separate data class to keep it in one place.

Test class without the test data.

SubtitleDownloaderTests.cs

That solved the problem of overfilled test class, but data provider class still gives me itches. My guess at this point is further extraction. I remember Uncle Bob doing 'extract till you drop' thing in one of his videos. This made me laugh, but also realize that there's huge benefit in making all the methods/classes as small as possible. After year in huge legacy project I understood that readible and self explainatory code is a gem that we should care about each time the opportunity is given. But that's something for the next session.