views:

58

answers:

5

Let's say you have some code like this (in a made-up langague, since it does not matter for this question):

constant float PI = 3.14;
float getPi() 
{ 
   return PI;
}

Would you test it like this:

testPiIs3point14()
{
   // Test using literal in test case
   AssertEquals( getPi(), 3.14 );
}

Or like this:

testPiIs3Point14()
{
   // Test using constant from implementation in test case
   AssertEquals( getPi(), PI );
}

In other words, do you use constants from your system under test in your test cases? Or is this considered an implementation detail?

+1  A: 

Definitely the second form, the purpose of the constant is to not introduce a "magic number". Now, in unit tests, you tend to use magic numbers quite a bit and that's OK.

In this case, you introduced a constant AND used a magic number. I would either use the constant everywhere or not use it at all.

Igor Zevaka
+1  A: 

I think there are two distinct cases here:

  1. If you are testing a constant that is critical to the result of a calculation, as in your example, I think it's better to use an independent test rather than re-using the same constant from the code you are trying to test. Instead of testing the constant value directly, I would test (for example) the function CalculateAreaOfCircle(), which would verify that the Area formula is correct and at the same time verify the value of PI.

  2. I think it makes sense to re-use enumerations and other constants that do not directly affect the outcome of critical parts of the code.

MrUpsideDown
I wanted to make a very simple example.
WW
Understood - I have revised my answer accordingly.
MrUpsideDown
+2  A: 

The two tests serve different purposes.

The first one ensures that getPi() will always return 3.14. It covers both the constant and the function and will fail if ever someone find the PI value used in the software is not accurate enough and replace it with, say 3.14159. This can be good or bad, depending on the context.

While the second form only covers the function. It will not fail if someone changes the constant ; it will only fail if the function is modified to return another constant (with a different value).

Choosing between the two depends on the objective of the test. Use a literal if the constant must never change. Use the constant to pin down the behavior of the function: return a constant - whatever its value. In the second case the test may be needless.

philippe
+1  A: 

I think this is the question about coupling between the tests and the production code. When I first started TDD I thought that having the constant in the tests makes the tests more thorough. However, now I think it just causes tighter coupling between the tests and the implementation. Does it make it more safe if you copy and paste the constant to the test? Not really. It just makes it more painful to change the constant, especially if its copy-pasted to multiple tests. These tests don't test if it is the right constant, they just test that this constant is returned from the method, so now I would definitely go for test number two.

Grzenio
+1  A: 

I use the first form - even though it duplicates the value (twice only), it is more readable.

[Test]
public void GetPIReturns3_14()
{
  Assert.AreEqual(3.14, testSubject.GetPI());
}

The duplication is necessary because if you reuse the constant as in the second test, you are not really testing anything. In effect, you're testing "Is Constant == Constant?". This test would never fail. e.g. if I change PI to be 1010.1010, the second test wouldn't fail.

Gishu