Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test methods that call other methods in a domain object

When working with Domain Objects, how do you typically unit test a method that calls another method in the object? For example:

public class Invoice
{
  public IList<InvoiceLine> InvoiceLines;
  public string Company;
  public bool IsDiscounted;
  public DateTime InvoiceDate;
  //...
  public GetTotalAmt();
  public GetExtendedTotalAmt();

  public decimal GetTotalAmt()
  {
    decimal total;
    foreach (InvoiceLine il in InvoiceLines)
    {
      total += il.Qty * il.Price;
    }
    return total;
  }

  public decimal GetExtendedTotalAmt()
  {
    decimal discount;
    if (IsDiscounted)
      discount = .05M; 
    return GetTotalAmt() * discount;
  }
}

Unit testing GetTotalAmt() is easy, but with GetExtendedTotalAmt() I'd have to use stub/mock InvoiceLine objects to make it work, when all I really want to do is test that a discount is applied if the IsDiscounted flag is true.

How do other people handle this? I don't think it makes sense to split up the domain object since these methods are both considered part of the core Invoice functionality (and splitting it would likely cause developers to call the wrong method more often).

Thanks!

like image 884
Andrew Avatar asked Oct 15 '22 10:10

Andrew


2 Answers

You could make the GetTotalAmt method virtual and then:

var sut = new MockRepository().PartialMock<Invoice>();
sut.Expect(x => x.GetTotalAmt()).Return(10);
sut.Replay();

var result = sut.GetExtendedTotalAmt();
like image 190
Darin Dimitrov Avatar answered Oct 18 '22 13:10

Darin Dimitrov


I would build up a situation which is as simple as possible: only one InvoiceLine with a Quantity and Price of 1.

Something like this:

invoice.Add(new InvoiceLine(new Article("blah", 1M), 1));

Assert.AreEqual(0.95M, invoice.GetExtendedTotalAmt());

When you find that this stuff gets quite complicated, finding errors gets hard etc, then it is a sign that you should split the class (making the calculations on the invoice a strategy or something similar). But as long as it is as simple as you piece of code here, I wouldn't worry about it.

like image 40
Stefan Steinegger Avatar answered Oct 18 '22 14:10

Stefan Steinegger