CaffGeek
CaffGeek

Reputation: 22054

Moq: Verifying protected method on abstract class is called

This is my test

[TestClass]
public class RepositoryTests
{
    private APurchaseOrderRepository _repository;

    [TestInitialize]
    public void TestInitialize()
    {
        _repository = new FakePurchaseOrderRepository();
    }

    [TestMethod]
    public void RepositoryGetPurchaseOrdersForStoreCallsValidatePurchaseOrders()
    {
        var store = new Store();
        var mockRepo = new Mock<APurchaseOrderRepository>();
        mockRepo.Protected().Setup("ValidatePurchaseOrders", ItExpr.IsAny<List<PurchaseOrder>>());

        _repository.GetPurchaseOrders(store);

        mockRepo.Protected().Verify("ValidatePurchaseOrders", Times.Once(), ItExpr.IsAny<List<PurchaseOrder>>());
    } 
}

APurchaseOrderRepository and it's interface look like this

public interface IPurchaseOrderRepository
{
    List<PurchaseOrder> GetPurchaseOrders(Store store);
}

public abstract class APurchaseOrderRepository : IPurchaseOrderRepository
{
    public abstract List<PurchaseOrder> GetPurchaseOrders(Store store);

    protected virtual bool ValidatePurchaseOrders(List<PurchaseOrder> purchaseOrders)
    {
        return true;
    }
}

And my Fake

public class FakePurchaseOrderRepository : APurchaseOrderRepository
{
    public override List<PurchaseOrder> GetPurchaseOrders(Store store)
    {
        var purchaseOrders = new List<PurchaseOrder>();

        ValidatePurchaseOrders(purchaseOrders);

        return purchaseOrders;
    }
}

However, my test fails with:

Test method PreSwapTests.RepositoryTests.RepositoryGetPurchaseOrdersForStoreCallsValidatePurchaseOrders threw exception: Moq.MockException: Expected invocation on the mock once, but was 0 times: mock => mock.ValidatePurchaseOrders(It.IsAny())

Configured setups: mock => mock.ValidatePurchaseOrders(It.IsAny()), Times.Never No invocations performed.

What am I doing wrong?

Notes:

Update:

I think it is this line mockRepo.Protected().Setup("ValidatePurchaseOrders");, because I need to add the parameters to it as a second argument, but I can't seem to get it correct.

Update 2: Made some modifications, now it compiles, but isn't counting correctly...or something, error message and code are both updated above.

Upvotes: 3

Views: 2825

Answers (2)

CaffGeek
CaffGeek

Reputation: 22054

Realized I was doing this all wrong, changed my objects to work with this test

    [TestMethod]
    public void RepositoryGetPurchaseOrdersForStoreCallsValidatePurchaseOrders()
    {
        var store = new Store();

        var mockPurchaseOrderProvider = new Mock<IPurchaseOrderProvider>();
        var mockPurchaseOrderValidator = new Mock<IPurchaseOrderValidator>();
        var purchaseOrderRepository = new PurchaseOrderRepository(mockPurchaseOrderProvider.Object, mockPurchaseOrderValidator.Object);

        mockPurchaseOrderValidator.Setup(x => x.ValidatePurchaseOrders(It.IsAny<List<PurchaseOrder>>()));

        purchaseOrderRepository.GetPurchaseOrders(store);

        mockPurchaseOrderValidator.Verify(x => x.ValidatePurchaseOrders(It.IsAny<List<PurchaseOrder>>()), Times.Once());
    }

This is a much better structure now I think.

Upvotes: 1

It's because ValidatePurchaseOrders is not in your IPurchaseOrderRepository interface.

The repository is declared as private IPurchaseOrderRepository _repository; so it can only see what is in the interface.

Upvotes: 0

Related Questions