简体   繁体   中英

Unit Testing how I think to point logical mistake on class which is under test

I m reading Art of Unit testing book and I try to understand state based testing logic.In an example of subject there was a calculator class like

public class Calculator
{
    private int sum=0;
    public void Add(int number)
    {
      sum+=number;
    }
    public int Sum()
    {
      int temp = sum;
      sum = 0;
      return temp;
    }
 }

and book shows how can we test this as:

[TestFixture]
public class CalculatorTests
{
    private Calculator calc;

    [SetUp]
    public void Setup()
    {
        calc = new Calculator();
    }

    [Test]
    public void Sum_NoAddCalls_DefaultsToZero()
    {
        int lastSum = calc.Sum();
        Assert.AreEqual(0,lastSum);
    }

    [Test]
    public void Add_CalledOnce_SavesNumberForSum()
    {
        calc.Add(1);
        int lastSum = calc.Sum();
        Assert.AreEqual(1,lastSum);
    }

    [Test]
    public void Sum_AfterCall_ResetsToZero()
    {
        calc.Add(1);
        calc.Sum();
        int lastSum = calc.Sum();
        Assert.AreEqual(0, lastSum);
    }

}

So until this, everything is great but, lets say I m writing a calculator class as much as that class, and i made method like

public int Sum()
{

  return sum;

}

and
Test class like

 [TestFixture]
public class CalculatorTests
{
    private Calculator calc;

    [SetUp]
    public void Setup()
    {
        calc = new Calculator();
    }

    [Test]
    public void Sum_NoAddCalls_DefaultsToZero()
    {
        int lastSum = calc.Sum();
        Assert.AreEqual(0,lastSum);
    }

    [Test]
    public void Add_CalledOnce_SavesNumberForSum()
    {
        calc.Add(1);
        int lastSum = calc.Sum();
        Assert.AreEqual(1,lastSum);
    }
}

Let say I didnt good realize when i writing code and when i write unit test for that How I catch that following bug? Because bug is that sum will not be zero after 2 add method like following processes

add(1)
add(23)
sum()  is 24 now
add(11)
add(12)
sum()  => will be 47 but it has to be 23.

So how i think to get that logical mistake when i write unit test.(if i write it NUnit will tell me there is a mistake) then i come back and will see the point and I will change calculator class like

public int Sum() 
{ 
  int temp = sum; 
  sum = 0; 
  return temp; 
}


I hope you understand what i try to say.
Thanks.

Basically you can't find all the edge cases for sure. However, you can specify what you intend the code to do and write clean code. If a calculator is supposed to reset its sum after asking for its sum, then that's part of the 'spec' that there should be a test for, its a 'requirement' invented by someone, so that should be easy to remember to write a test for.

The harder thing is all the edge cases created by the way something is coded. I used to do coding interviews where I would write unit tests for candidates code. I thought I had a good suite of tests to prove something worked. But I quickly found, that people can code things in ways that introduce hard to test for edge cases ( like something will fail on the 9th time it does something that seems like it should work every single time ). So mainly, if you follow the advice of TDD, write a test, write the code to make it pass, refactor to make the code clean, you won't go too far wrong.

and remember, this is not a magic bullet, this isn't some magic formula which allows you to write perfect code. You still need to think think think about what you are doing.

It sounds like you've basically already got a test case:

[Test]
public void CallingSumResets()
{
    var calc = new Calculator();
    calc.Add(10);
    Assert.AreEqual(10, calc.Sum());
    Assert.AreEqual(0, calc.Sum());
}

The test that it's actually performing addition would be done in other tests - this is just testing that after you call Sum the first time, it resets the internal state.

This test should fail:

   [Test]
    public void Sum_AfterCall_ResetsToZero()
    {
        calc.Add(1);
        calc.Sum();
        int lastSum = calc.Sum();
        Assert.AreEqual(0, lastSum);
    }

until you changed your code to reset the sum after Sum() is called. However, I would prefer to create a separate method Clear() rather than reset the sum in your getter.

TDD steps

  1. Think what you want the Calculator to do.
  2. Write a test for it.
  3. Write code to pass test.

If I understand you correctly, the sample code below is your implementation, and has a bug; It does not reset the sum value to zero as the correct implementation does, giving an error. Your question is, how to write a unit test for this?

public int Sum()
{

  return sum;

}

Assuming I've interpreted your question correctly, you should simply write a test that detects whether the value is zero when invoked a second time:

add(11)
add(12)
sum() => ignore result
sum() => Should be zero

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM