I'm writing some N-Unit tests and I'm having a little difficulty. I'm trying to wire up a Test to a TestCaseSource
in my code, but it doesn't seem to be constructing the objects correctly.
Here is my Test Method:
[Test, TestCaseSource(typeof(TestCaseStuff), "GetTestCases", Category = "Release")]
public void WithdrawMoney(TestCaseStuff tc)
{
double newBalance = AccountBalance - tc.amt;
if (newBalance < 0)
{
Assert.Fail(String.Format("You can't withdraw {0}! You've maxed" +
"out your bank account.", tc.amt.ToString("C2")));
}
AccountBalance = newBalance;
Assert.Pass(String.Format("Your new balance is {0}.",
(AccountBalance).ToString("C2")));
}
And my TestCaseSource
:
public class TestCaseStuff
{
public double amt { get; set; }
public TestCaseStuff()
{
Random rnd = new Random();
this.amt = rnd.Next(0, 20);
}
[Category("Release")]
public IEnumerable<TestCaseData> GetTestCases()
{
for (int i = 0; i < 500; i++)
{
yield return new TestCaseData(this);
}
}
}
The is mostly serving as proof of concept, so that when it comes time to write an actual test with complex objects, I'll know that I can just write a loop like the one above and put random values in my object. However, every instance of TestCaseStuff
that is returned to my test method is the same.
Update:
The answer below is correct. When I was passing it into N-Units TestCaseData
object, I assumed (incorrectly) that it would simply pass that instance in by value. Apparently, it is done by reference which is why the value was always the same.
On top of that, I was using the Random
class incorrectly. It isn't something I deal with usually, but I failed to read up on it properly. As explained in the link below, when using Random
with it's default constructor, the seed value is derived from the system clock. As a result, if you instantiate several Random
objects in quick succession they will share the same default seed value and produce the same values.
So, as a result of these developments, my code now reads:
public class TestCaseStuff
{
public double amt { get; set; }
private static readonly Random rnd = new Random();
public TestCaseStuff()
{
this.amt = rnd.Next(0, 20);
}
[Category("Release")]
public IEnumerable<TestCaseData> GetTestCases()
{
for (int i = 0; i < 500; i++)
{
yield return new TestCaseData(new TestCaseStuff());
}
}
}
The above code will only instantiate one copy of
TestCaseSource
and keep on feeding the same value.If the intention is to generate a random number in every loop, I think you should make a static instance of the
Random
object and generate a number from it every time you create a newTestCaseStuff
object.I would rewrite the TestCaseStuff like this: