Unit Testing - What do you do when your code is pretty much just a calculation (GetHashCode for example)? [duplicate]
public class Foo
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public override int GetHashCode()
{
var hash = 17;
hash *= 23 + x.GetHashCode();
hash *= 23 + y.GetHashCode();
hash *= 23 + z.GetHashCode();
}
}
When you go to Unit Test the GetHashCode, I'm torn between calculating the original components and repeating the function or using a predetermined value:
[TestMethod]
public void Test1
{
var x = 1; y = 2; z = 3;
var foo = new Foo() { X = x, Y = y, Z = z };
var hash = 17;
hash *= 23 + x.GetHashCode();开发者_开发技巧
hash *= 23 + y.GetHashCode();
hash *= 23 + z.GetHashCode();
var expected = hash;
var actual = foo.GetHashCode();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void Test2
{
var x = 1; y = 2; z = 3;
var foo = new Foo() { X = x, Y = y, Z = z };
var expected = ? //Some predetermined value (calculated by hand?)
var actual = foo.GetHashCode();
Assert.AreEqual(expected, actual);
}
Or is there some other way?
Unit testing is for testing logic. Is the GetHashCode
calculation itself logic? Not really, although opinions may vary.
The relevant logic here is that two objects that are equal have the same hash code, i.e. Equals
and HashCode
are compatible. Or, quoting from the docs:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
So I would write unit tests that guarantee that those conditions are met, not that the internal implementation of GetHashCode
matches a predetermined procedure.
Both of your example tests are highly brittle, and perfectly valid GetHashCode
implementations would fail them. Recall that one of the major purposes of unit tests is to allow refactoring without fear. But, nobody can refactor GetHashCode
without your unit tests breaking.
I compare the result against pre-computed values with lots of commenting to explain why I chose the values being tested.
For pure calculations, I tend to write unit tests so that they ensure the function keeps the conditions that are required/expected of the code that will use it.
Example conditions:
- Are there any constraints on the generated hash value? min value, max value, odd, even, etc.
- Does it properly hash positive and negative numbers?
- Does it create unique values under the appropriate conditions?
精彩评论