views:

33

answers:

1

Hello,

I've read through some of the discussions on the Moq user group and have failed to find an example and have been so far unable to find the scenario that I have. Here is my question and code:

// 6 periods
var schedule = new List<PaymentPlanPeriod>()
{
    new PaymentPlanPeriod(1000m, args.MinDate.ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(1).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(2).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(3).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(4).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(5).ToString())
};

// Now the proxy is correct with the schedule
helper.Setup(h => h.GetPlanPeriods(It.IsAny<String>(), schedule));

Then in my tests I use Periods but the Mocked _PaymentPlanHelper never populates the collection, see below for usage:

public IEnumerable<PaymentPlanPeriod> Periods
{
 get
 {
  if (CanCalculateExpression())
     _PaymentPlanHelper.GetPlanPeriods(this.ToString(), _PaymentSchedule);

  return _PaymentSchedule;
 }
}

Now if I change the mocked object to use another overloaded method of GetPlanPeriods that returns a List like so :

var schedule = new List<PaymentPlanPeriod>()
{
    new PaymentPlanPeriod(1000m, args.MinDate.ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(1).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(2).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(3).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(4).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(5).ToString())
};

helper.Setup(h => h.GetPlanPeriods(It.IsAny<String>())).Returns(new List<PaymentPlanPeriod>(schedule));

List<PaymentPlanPeriod> result = new _PaymentPlanHelper.GetPlanPeriods(this.ToString());

This works as expected. Any pointers would be awesome, as long as you don't bash my architecture... :)

Thank you, Stephen

+1  A: 

Hi

The Setup-Method is basically to setup some expeced behavior. For example to setup a Mock-Instance to return certain values. For example a configuration-mock:

var configMock = new Mock<IConfiguration>();
configMock.Setup(c=>c.GetSetting("Title")).Returns("Hello Word");
configMock.Setup(c=>c.GetSetting("Answer")).Returns("42");

This means, than when you pass "Title" to the GetSetting-Method the mock will return "Hello Word". And when you pass "Answer" to the mock, it will return "42". Addionally you can configure wildcards. For example:

var configMock = new Mock<IConfiguration>();
configMock.Setup(c=>c.GetSetting(It.IsAny<String>())).Returns("Hello Word");

Now the mock will return for any call to the GetSetting-Method the string "Hello World"

Now in your first case you set up the mock in this way: Expect a call to GetPlanPeriods with any string and this list. So with the second parameter you specify which list you expect. But you don't setup any bahvior for this call.

Afaik you can setup Moq to something with the arguments. Like this:

helper.Setup(c => c.GetPlanPeriods(It.IsAny<string>(),It.IsAny<List<PaymentPlanPeriod>>()))
            .Callback((string s, List<PaymentPlanPeriod> l)=>
                          {
                              l.Add(new PaymentPlanPeriod(1000m, args.MinDate.ToString()));
                          });

In the second example you set up the mock in this way: Expect a call to GetPlanPeriods with any string and return then this list. So it will return for any call the given list. Thats why it works.

I general I would recommend to design your API in such a way that you're second example. Prefer to return the changed collection instead of updating the passed collection. Using and mocking such methods is way easier.

Gamlor