13

I am learning to create simple Unit tests to eventually (and hopefully) start to do only TDD; for now I am trying to write tests for code already written to see what might cause problems. This is one of them.

Let's say I have this simple class (with Typescript-> Javascript):

class PrivateStuff {
    greeting: string;
    private _thisIsPrivate;

    constructor(isPrivate: boolean) {
        this._thisIsPrivate = isPrivate;
    }

    setPrivate(option) {
        this._thisIsPrivate = option;
        console.log("_thisIsPrivate changed to : " + option);
    }

    getPrivate() {
        console.log("_thisIsPrivate is : " + this._thisIsPrivate);
        return this._thisIsPrivate;        
    }
}

And I use it in this way:

let privateStuff = new PrivateStuff(false);

let buttonSet = document.createElement('button');
buttonSet.textContent = "Set True";
buttonSet.onclick = function () {
    privateStuff.setPrivate(true);
}

let buttonGet = document.createElement('button');
buttonGet.textContent = "Get";
buttonGet.onclick = function() {
    console.log(privateStuff.getPrivate());
}
document.body.appendChild(buttonSet);
document.body.appendChild(buttonGet);

setPrivate() does not need to return anything, but because of that I cannot test it. When creating a unit test for it, should I refactor the code?

If I were doing TDD, should I always create methods that return something just to be able to test it? Or I am missing something?

P.S. You can see and run the code here

10
  • 4
    If you setPrivate wouldn't the value of getPrivate tell you if it worked?
    – JeffO
    Feb 15, 2017 at 5:44
  • @JeffO yes, I see now that I do no just have to use the function's return to check if it worked.
    – distante
    Feb 15, 2017 at 5:48
  • "setPrivate() does not need to return anything, but because of that I cannot test it." Does it induce any observable effect? If so, you can test it. Otherwise, there is no interest in testing it (and there is no interest in implement it).
    – mgoeminne
    Mar 21, 2017 at 15:25
  • @mgoeminne What if the method is void and writes to the database/log or sends a message to another object as its only effect?
    – Andres F.
    Mar 21, 2017 at 15:31
  • @AndresF. You can read from the database/log or mock the other object to confirm that the data was sent. It may not be a "unit" test, but that's not what actually matters. Mar 21, 2017 at 16:29

1 Answer 1

24

I guess your misconception here is that a "subject under test" must be always a method on its own. But that is not true, though some methods can be tested without using any other methods, the typical size of a SUT is a class, or some interacting methods and functions of one class. So if you have a method which changes the internal state of an object, there must be always some externally visible change to the behaviour of that object (otherwise it would not make any sense to have the method in the first place). And in a unit test, you can validate exactly this behaviour.

For example, lets say you have a class NumberFormatter with a responsibility to format floating point numbers in a predefined way. Lets assume it contains a method FormatToString(double d). Let's further assume it has a method setDecimalSeparator, but no getDecimalSeparator. Nethertheless you can easily write a test if after a call to setDecimalSeparator the method FormatToString behaves in a desired way. Such a test could look like this

  var nf = new NumberFormatter();
  nf.setDecimalSeparator(".");
  AssertEqual("12.34",nf.FormatToString(12.34))
  nf.setDecimalSeparator(",");
  AssertEqual("12,34",nf.FormatToString(12.34))

So this is a meaningful test of setDecimalSeparator, a method without a return value.

1
  • I see, so in my unrealistic example I could use the ´getPrivate()´ function to see if ´_thisIsPrivate´ had change and muss asume that ´getPrivate()´ works but in a more real case scenario should I test the object being changed. Thank you for your clear explanation!
    – distante
    Feb 15, 2017 at 5:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.