interface IPoint
{
int X { get; }
int Y { get; }
}
static bool CoincidesWith(this IPoint self, IPoint other); // implementation unknown
I want to write a NUnit test that verifies my assumption about the meaning of CoincidesWith
:
self.CoincidesWith(other)
⇔ (self.X
=other.X
) ∧ (self.Y
=other.Y
)
The following is the most succinct test I've been able to come up with so far:
[Theory]
void CoincidesWith_Iff_CoordinatesAreEqual(IPoint self, IPoint other)
{
bool coordinatesAreEqual = (self.X == other.X && self.Y == other.Y);
Assert.That(self.CoincidesWith(other) == coordinatesAreEqual);
}
My questions, in descending order of importance, are:
[Theory]
, is it considered wrong, or bad style, to use Assert.That
instead of Assume.That
? ( The documentation seems to suggest that the latter should be used in conjunction with [Theory]
. ) [Theory]
rather than a [Test]
? After some more thought, I've come to the conclusion that there is nothing wrong with my above solution.
Is this case indeed more suitable for a
[Theory]
rather than a[Test]
?
If the implementation for the CoincidesWith
method were available for inspection (eg as source code), or at least well-documented, then there would be no need to make assumptions — I could simply look up what I need to know. In that case, a [Test]
— or, as xUnit.net calls tests, a [Fact]
— would seem more appropriate.
But since I have no access to the implementation for CoincidesWith
, and the documentation is insufficient, I do need to make some assumption, or [Theory]
, about the general working of the method.
With
[Theory]
, is it considered wrong, or bad style, to useAssert.That
instead ofAssume.That
?
No. It's just another tool to be used, and neither less nor more appropriate than Assert.That
.
In the context of a [Theory]
, Assume.That
would seem to be the right means of putting additional constraints on the supplied [Datapoints]
, while verifying the actual assumption (using those datapoints that make it past Assume.That
) is left to Assert.That
.
An example can illustrate this. Let's try to write a test for this assumption:
Given an even integer
a
and an odd integerb
, their producta * b
is even.
Testing if a * b
is even only makes sense once the preconditions are met. If a
is not an even integer, or b
is not an odd integer, the test should neither succeed nor fail; it should be inconclusive. And that's exactly what Assume.That
helps achieve. The actual test, however, is left to Assert.That
:
[Theory]
void GivenAnEvenIntegerAndAnOddInteger_ProductIsAnEvenInteger(int a, int b)
{
Assume.That(a.IsEven());
Assume.That(b.IsOdd());
// note: the type system already ensures that `a` and `b` are integers.
int product = a * b;
Assert.That(product.IsEven());
// note: the theory doesn't require `product` to be an integer, so even
// if the type system didn't already assert this, we would not test for it.
}
[Datapoints]
int[] integers = { 1, 2, 3, 4, 5, 6, 7 };
static bool IsEven(this int integer) { … }
static bool IsOdd(this int integer) { … }
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.