mercredi 31 décembre 2014

Is Moq mocking a subinterface return value and ignoring the intermediary step a bug or a feature?

I was recently building an app and a coworker wrote a setup I swore would fail. I was wrong. In it a factory method was set up with an expected value of true and would return an integer. Because we didn't mock our configuration, the bool would always be false.


The setup was:



var homeStoreDataServiceFactory = new Mock<IHomeStoreDataServiceFactory>();
homeStoreDataServiceFactory.Setup(service => service.Create(true).GetStoreNumber())
.Returns(5);


I thought that a call to factory.Create(false) would not generate the mock object, and thus we would get 0 for the integer instead of the mocked value 5. Instead, no matter what we changed the service.Create(X) to, calls to GetStoreNumber always return 5 as if we'd used It.IsAny().


I've built up an MVCE so that you can see what I'm confused about:



using System;
using Moq;

namespace MoqBugMCV
{
public interface IItemServiceFactory
{
IItemService Create(bool shouldCreateServiceA);
}

public class Item
{
public string Name { get; set; }
public decimal Price { get; set; }
}

public interface IItemService
{
Item GetItem();
}

public class ItemManager
{
private readonly IItemService _itemService;

public ItemManager(IItemServiceFactory itemServiceFactory)
{
_itemService = itemServiceFactory.Create(true); //<==== configured true (like by app.config at runtime or something)
}

public Item GetAnItem()
{
return _itemService.GetItem();
}
}

internal class Program
{

private static void Main(string[] args)
{
var itemServiceFactory = new Mock<IItemServiceFactory>();
var chrisItem = new Item {Name = "Chris's Amazing Item", Price = 1000000};
itemServiceFactory.Setup(factory => factory.Create(true).GetItem())
.Returns(chrisItem);

var itemManager = new ItemManager(itemServiceFactory.Object);

var theItem = itemManager.GetAnItem();

Console.WriteLine("The item is {0} and costs {1}", theItem.Name, theItem.Price);

var itemServiceFactoryBroken = new Mock<IItemServiceFactory>();
itemServiceFactoryBroken.Setup(factory => factory.Create(false).GetItem()).Returns(chrisItem); //expecting this to fail, because IItemServiceFactory.Create(true) is configured

itemManager = new ItemManager(itemServiceFactoryBroken.Object);
theItem = itemManager.GetAnItem();

Console.WriteLine("The item is {0} and costs {1}", theItem.Name, theItem.Price); //would expect the item would be null or values to be blank
}
}
}


So... is this a bug or feature, or am I not understanding something about Moq?


Aucun commentaire:

Enregistrer un commentaire