0

Let's say I have a class which has a method to calculate something (it doesn't really matter what). It could look something like this:

class Example 
{
    public int CalculateStuff(int inputValue) 
    {
        // ...some logic here
    }
}

But the inputValue is always taken from the class itself. So it instead it could look like this:

class Example
{
    public int InputValue { get; set; }
    
    public int CalculateStuff()
    {
        // ...calculate something from 'InputValue'
    }
}

Now this is great, but I would like to add a unit test to CalculateStuff(), so here is my question:

What is the best way to make a clear test? I could simple set the value on the class in the test, like this:

void UnitTest()
{
     var example = new Example();
     example.InputValue = 42;
     Assert.AreEqual(84, example.CalculateStuff());
}

However, I could also make CalculateStuff() a static method, with a non-static overload, and then test the static part. The advantage of this (as far as can tell) is that it would also work in the scenario where the InputValue is something like DateTime.Now:

class Example
{
    public int InputValue { get; set; }
    
    public int CalculateStuff()
    {
        return CalculateStuff(InputValue);
    }

    public static int CalculateStuff(int inputValue)
    {
        // ...calculate something from 'inputValue'
    }
}

void UnitTest()
{
    Assert.AreEqual(84, Example.CalculateStuff(42));
}

Is there a widely accepted way of doing this? And if so, which? Or does it depend on the specific case?

Update

Another example, which is slightly different (but in the same category) is if the input was of type DateTime which in production always used DateTime.Now as input (like calculating the time since some event). That would mean that the Example class always had a property with value DateTime.Now, if following the first approach:

public int CalculateDateStuff(DateTime untilDtm) 
{
    // ...logic and stuff
}

Which is then called like this:

var result = example.CalculateDateStuff(DateTime.Now);

...at least if it is to be testable.

Jakob Busk Sørensen
  • 5,599
  • 7
  • 44
  • 96
  • 2
    The former seems pretty simple, I see no advantage to the latter. What problem have you encountered with the former? – David Jul 14 '20 at 11:49
  • @David that if the input value is a `DateTime` and the value is always `DateTime.Now` for example. That way you would have to make a property on the `Example` class, which is always set to `DateTime.Now`, which seems a bit odd. – Jakob Busk Sørensen Jul 14 '20 at 11:51
  • 1
    Is it TDD? Why do you say "I could also make"? As for to make method static or not, it's [another story](https://stackoverflow.com/q/169378/1997232). – Sinatr Jul 14 '20 at 11:52
  • 2
    I see no difference in both. You'll test exactly same algorithm. But in general, I would test objects and methods as they are used in code. So first option IMO is the way to go. Especially, when method depends on private variables/state of an object. – Michał Turczyn Jul 14 '20 at 11:52
  • @JakobBuskSørensen: There's no `DateTime` in the code shown. And if the input must always be `DateTime.Now` then why does it need to be provided? Why can't the method just use `DateTime.Now`? It's still not clear to me what problem you're trying to solve. – David Jul 14 '20 at 11:54
  • @David I know. I was looking for whether or not there was a dessign pattern(-ish) for this type of problem. So the problem is more generic than the example. If there is no pattern, and "it depends", that also fine. That way I know, it's just a matter of opinion :-) – Jakob Busk Sørensen Jul 14 '20 at 11:57

3 Answers3

1

You should not add additional methods, just to test other methods. What you are doing is correct. Generally, a unit test consists of 3 steps (naming of the steps may vary):

  1. Setup: Prepare everything needed for your tests.
  2. Action: Run the method you want to test.
  3. Assert: Check the result of the actions against what you expect the output to be.

In your case:

void UnitTest()
{
    //Setup
    var example = new Example();
    example.InputValue = 42;

    //Action
    var result = example.CalculateStuff()

    //Assert
    Assert.AreEqual(84, result);
}
Florian H.
  • 89
  • 10
0

This is just my opinion, but if you are using Unit Testing, you have to try testing exactly what you normally do with your code. Using different input, but just like you use.

The first example, seems like a case that you use in your code: you create a class, fill it and the call the method.

The second, in my opinion, seems like overcomplicating all the situation, because it is not like the real case at all, and also you have to add code for each specific situation.

Imagine a case in which you have 10 property and 10 methods: how much this class can grow?

Emanuele
  • 723
  • 4
  • 15
0

a clear test can only be written if you have clear code.

your first example where you pass what is needed to your method is the easiest way to do this.

Why? Simply because the input is part of the method under test. If your input is part of class itself then you lose clarity. That code may be simple now, but later it can easily become something else. You now have data which lives outside of your method under test, which means now you have to maintain state. Don't do that.

In terms of other types of data like DateTime, the answer is the same, your datetime value is a parameter and you can pass DateTime.Now to your method.

Bottom line, given a choice, I would stick to this construct all the time:

public int CalculateStuff(int inputValue) 
    {
        // ...some logic here
    }
Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32