Over a million developers have joined DZone.

Test Attribute #9 – Deterministic

· DevOps Zone

The DevOps Zone is brought to you in partnership with Sonatype Nexus. The Nexus Suite helps scale your DevOps delivery with continuous component intelligence integrated into development tools, including Eclipse, IntelliJ, Jenkins, Bamboo, SonarQube and more. Schedule a demo today

 This is the 9th post in the Test Attribute series that started here. To learn more about testing, contact me.

I keep hammering on trust and how it’s crucial that we trust our tests. If a test is deterministic, it raises the level of our trust.  If it isn’t, we may question its result, which will be followed by questioning other tests as well.

Let’s start with a simple example. What’s wrong with this picture?

publicclass CreditCard
{
    DateTime expirationDate =new DateTime(2017,12,15);
    publicbool IsExpired()
    {
        return (DateTime.Now > expirationDate);
    }
}


This is the tested code. So we can write this test:

[TestMethod]publicvoid IsExpired_Today_False()
{
    var card =new CreditCard();
    Assert.IsFalse(card.IsExpired());
}

Which passes. Until a specific day arrives, and then it fails.
Or this code:
public class Settings
{
    public string GetFirstValue()
    {
        var lines = File.ReadLines("config.sys");
        return lines.First();
    }

And its test:
public class Settings
{
    public string GetFirstValue()
    {
        var lines = File.ReadLines("config.sys");
        return lines.First();
    }

That passes, as long if finds the file where it expects it, or somebody edits it “the wrong way”.
These may look like dependencies we can’t trust all the time.  It’s more deep than that.

Never Assume

keep-calm-and-assume-nothing-6When we write code, we have many assumptions. The “happy path” we usually code first, when we assume nothing will go wrong. The other paths are the the paths where something might go wrong. Unfortunately, we can test and code only the things we think of. Actually, writing helps us think of other cases. The downside, is that if we use a library we didn’t write, we think less of the side effects.

To make sure we remove uncertainty from our tests, we need to remove being dependent on:
  • Geographical location
  • Time
  • Hardware speed, CPU, memory
  • Files and data, both existing and missing
The obvious solution is to mock the dependencies, or setup the system to be independent. By mocking the date we can check the “before” and “after” cases, or “plant” the file there and simulate reading it.

However, mocking comes with its owndrawbacks, so you should consider the tradeoff.

And sometimes, mocking isn’t an option. We had a performance test, that was supposed to run under a certain limit. It started failing and passing on and off. Instead of checking the problem we said: “Oh, leave it, this test is just like that”. And we missed opportunities for fixing real problems.

To handle the root cause – assumptions, we’ll go back to our friends. Review the tests and code, and try to either validate the assumptions, or invalidate them (in that case, remove the code and test). Unverified assumptions may cause not only bugs. The code you’ve added will make it harder to add new code in the future. Use code that not only works, but that is also valid.

Next time: Isolation.

The DevOps Zone is brought to you in partnership with Sonatype Nexus. Use the Nexus Suite to automate your software supply chain and ensure you're using the highest quality open source components at every step of the development lifecycle. Get Nexus today

Topics:

Published at DZone with permission of Gil Zilberfeld, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}