3

My MongoDbRepository has an interface called IRepository. So I am mocking the interface to set up the method which is UpdateOneAsync. However my MerchantConfigurationRepository can only take a MongoDbRepository object which is why I need to cast it. For some reason when I do this

(MongoDBRepository<MerchantConfigurationEntity>)dataAccess.Object

I get the error

Unable to cast object of type 'Castle.Proxies.IRepository`1Proxy' to type 'Newgistics.Common.MongoDb.MongoDBRepository`1

How am I supposed to set up the Mock and then pass in the object, I tried setting a variable to the dataAccess.Object and passing in that variable, but if I do that the setup goes in as null.

Below you will find the unit test:

[Fact]
public async void UpdateMerchantSuccessPushesMerchantEntityToDataStore()
{
    //Arrange
    var originalMerchantConfig = ModelFactory.GetMerchant();
    var merchants = new List<MerchantConfigurationEntity>();

    var dataAccess = new Mock<IRepository<MerchantConfigurationEntity>>();

    dataAccess.Setup(m => m.UpdateOneAsync(It.IsAny<MerchantConfigurationEntity>()))
        .Callback((MerchantConfigurationEntity m) => merchants.Add(m))
        .Returns(Task.FromResult(1));

    var merchantRepo = new MerchantConfigurationRepository((MongoDBRepository<MerchantConfigurationEntity>)dataAccess.Object);

    //Act
    var result = await merchantRepo.UpdateMerchant(originalMerchantConfig);

    //Assert
    result.ShouldNotBeNull();
    result.Sucess.ShouldBeTrue();
    merchants.Count.ShouldBe(1);
    merchants[0].merchantId.ShouldBe(originalMerchantConfig.merchantId);
}
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
Lostaunaum
  • 697
  • 1
  • 10
  • 31
  • Your classes should be dependent on abstractions and not on concretions for this very reason. `MerchantConfigurationRepository` should be dependent on `IRepository` and not the implementation `MongoDBRepository` – Nkosi Jan 13 '17 at 17:53
  • Dude thank you for throwing some sense into my brain, of course DUH! – Lostaunaum Jan 13 '17 at 17:58
  • 1
    While @Nkosi is absolutely correct, Moq _can_ mock classes, as in `var dataAccess = new Mock>();` but it requires the class to be public (unless you make Moq's assembly a friend assembly) with a relevant accessible instance constructor for which you can pass "good" arguments, and it is only useful if the methods you need to `Setup` are `virtual` or `abstract` (including `override` without `sealed`) and accessible. If non-virtual members (including fields) are used, the class's own implementation will be used, of course. – Jeppe Stig Nielsen Jan 13 '17 at 18:15

1 Answers1

1

Your classes should be dependent on abstractions and not on concretions for this very reason. MerchantConfigurationRepository should be dependent on IRepository<MerchantConfigurationEntity> and not the implementation MongoDBRepository<MerchantConfigurationEntity>

public class MerchantConfigurationRepository {
    private readonly IRepository<MerchantConfigurationEntity> repository;

    public MerchantConfigurationRepository(IRepository<MerchantConfigurationEntity> repositiry) {
        this.repository = repository;
    }

    //...other code

    public Task<int> UpdateMerchant(Merchant model) { ... }
}

That way now you have more flexibility to use the mocked repository when testing in isolation.

var merchantRepo = new MerchantConfigurationRepository(dataAccess.Object);

Just make sure that your DI knows to use the actual implementation in production.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    Yes bro, you got it thats exactly what I did, thanks for posting your answer. Basically I had to change My repositories so they can consume the interface. I always do this mistake when using Moq, kinda of a pain that you have to change your code in order for UnitTests to work, but at the end of the day this is the desired structure. Once again thank you for your response you really did help me out. – Lostaunaum Jan 13 '17 at 18:38