Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Over my many years as a developer, I have noticed a pattern. This pattern is to do with unit tests. Especially those who write unit tests. What Iâve noticed is that a lot of developers donât treat their unit tests like they treat their (production) code. That is, they under-engineer unit tests and end up with unreadable tests that are impossible to debug, and no one understands what the tests are testing.
Using Constructors
If youâre using DI (Dependency Injection) in your production code, your test code usually requires a lot of set up. Weâve all seen this mess. new x(); new y(); new z(); Eventually, you end up with setup that takes half a page. But, luckily for you, there are patterns to deal with this. And I like the rule of using a constructor in as few places as necessary. What that means, is that you should dig into your patterns book and start by maybe using the Builder pattern.
public class RepositoryBuilder{ public RepositoryBuilder() { DbConnection = new MockDbConnection(); }
public IDbConnection DbConnection { get; set; }
public Repository Build() { return new Repository(DbConnection); }}
You donât have to follow the above, but basically, this will abstract away the constructor and set some defaults for you. You can set the DbConnection yourself if you need to test something specific with the behaviour between the DbConnection and the Repository. Now your tests will look like below, and you can even go further than that.
[TestFixture]public class RepositoryTests{ [Test] public void CanGetDataFromRepository() { var repository = new RepositoryBuilder().Build(); var expectedData = CreateExpectedData();
var data = repository.GetData();
data.ShouldBe(expectedData); }}
You can see that the code is readable. Thereâs no more copy+paste of constructors, which means that when you refactorâââitâll be so easy because youâll only have to change one place. Now, Iâm not saying that this rule is 100% correct, but when you can decouple your tests a little bit from the implementation, itâll go a long way to making your life easier.
Keep It Simple Stupid
Donât try to test multiple things in one unit test. If your method is doing more than one thing then maybe itâs time to consider refactoring that method. But donât worry! Thereâs help on the way. You can write multiple unit tests that test different things in your method. Maybe you have a decorator, and you want to test that what you add works and that youâre still calling into the class that youâre decorating. Thatâs okay! Just do it in two unit tests.
Mocking
I like mocking a classâs behaviour. I prefer it to creating a Stub class. There are tonnes of mocking frameworks out there. Thereâll probably be a mocking framework for your choice of language. For C#, I like to use Moqâââbut if someone could recommend a better mock frameworkâââIâd be up for it. For JSâââyou can see from my earlier posts that I like Jest. It does everything we need.
Fluent Syntax/Method Chaining
I like the Fluent Syntax for assertions and builders. It helps to create a story that whoever reads the test can follow and understand without having to look into the code. But you can go too overboardâââwhich is what has happened sometimes. Iâve seen people go crazy with the Given/When/Then phenomenon. An example:
[Test]public void DocusignTest(){ Given.ADocuSignService .ThatReturnsInvalidTempResult().GetDocuSignURL(Given.AHotelId) .ShouldNotBeNullOrEmpty();}
YES: Itâs readable
- YES: Itâs understandable.
- YES: Itâs short.
However, the minus points are:
- NO: Whatâs it testing?
- NO: Where do IÂ debug?
- NO: I canât glance at this test and understand the inner workings. Iâll have to go through every method to find out what each does.
I much prefer the syntax of âArrange, Act, Assertâ. You do you set up (arrange). You call the method in question (act). You determine the truth (assert).
[Test]public void DocusignTest(){ // arrange var service = Given.ADocuSignService.ThatReturnsInvalidTempResult();
// act var result = service.GetDocuSignURL(Given.AHotelId);
// assert result.ShouldNotBeNullOrEmpty();}
I find that much more understandable than the first example. Maybe you donât? Let me know how you structure your tests.
I hope that youâve learnt a little bit from this brief introduction to improving your tests. To summarise, use builders (or something similar) to decouple your tests from changes to the object youâre testing. Itâll make your refactoring that much easier. Keep your tests simple. Unit test one thing at a time. Try mocking! Itâll save you creating Stubs. And finally, try the fluent syntaxâââjust donât go too overboard.
Originally published at www.alexaitken.nz on June 18, 2018.
Treat Your Tests Like Your Code was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.