Reputation: 3399
I've been trying to wrap my head around unit testing and I'm trying to deal with unit testing a function whose return value depends on a bunch of parameters. There's a lot of information however and it's a bit overwhelming..
Consider the following:
I have a class Article
, which has a collection of prices. It has a method GetCurrentPrice
which determines the current price based on a few rules:
public class Article
{
public string Id { get; set; }
public string Description { get; set; }
public List<Price> Prices { get; set; }
public Article()
{
Prices = new List<Price>();
}
public Price GetCurrentPrice()
{
if (Prices == null)
return null;
return (
from
price in Prices
where
price.Active &&
DateTime.Now >= price.Start &&
DateTime.Now <= price.End
select price)
.OrderByDescending(p => p.Type)
.FirstOrDefault();
}
}
The PriceType
enum and Price
class:
public enum PriceType
{
Normal = 0,
Action = 1
}
public class Price
{
public string Id { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
public PriceType Type { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public bool Active { get; set; }
}
I want to create a unit test for the GetCurrentPrice
method. Basically I want to test all combinations of rules that could possibly occur, so I would have to create multiple articles to contain various combinations of prices to get full coverage.
I'm thinking of a unit test such as this (pseudo):
[TestMethod()]
public void GetCurrentPriceTest()
{
var articles = getTestArticles();
foreach (var article in articles)
{
var price = article.GetCurrentPrice();
// somehow compare the gotten price to a predefined value
}
}
I've read that 'multiple asserts are evil', but don't I need them to test all conditions here? Or would I need a separate unit test per condition?
How would I go about providing the unit test with a set of test data? Should I mock a repository? And should that data also include the expected values?
Upvotes: 3
Views: 3856
Reputation: 2801
I think you need datadriven testing. In vsts there is an attribute called Datasource, using it you can send a test method multiple test cases. Make sure you don't use multiple asserts. Here is one MSDN link http://msdn.microsoft.com/en-us/library/ms182527.aspx
Hope this will help you.
Upvotes: 2
Reputation: 1284
new test for each startup condition and single assert,f.e.
[Test]
public void GetCurrentPrice_PricesCollection1_ShouldReturnNormalPrice(){...}
[Test]
public void GetCurrentPrice_PricesCollection2_ShouldReturnActionPrice(){...}
and also test for boundaries
for unit tests i use pattern
MethodName_UsedData_ExpectedResult()
Upvotes: 2
Reputation: 1038820
You are not using a repository in this example so there's no need to mock anything. What you could do is to create multiple unit tests for the different possible inputs:
[TestMethod]
public void Foo()
{
// arrange
var article = new Article();
// TODO: go ahead and populate the Prices collection with dummy data
// act
var actual = article.GetCurrentPrice();
// assert
// TODO: assert on the actual price returned by the method
// depending on what you put in the arrange phase you know
}
and so on you could add other unit tests where you would only change the arrange
and assert
phases for each possible input.
Upvotes: 4
Reputation: 161773
You do not need multiple asserts. You need multiple tests with only a single assert each.
Upvotes: 2