模拟界面转换回原始 class

Mock Interface casting back to original class

我的 MongoDbRepository 有一个名为 IRepository 的界面。所以我正在模拟接口来设置 UpdateOneAsync 的方法。但是我的 MerchantConfigurationRepository 只能接受一个 MongoDbRepository 对象,这就是我需要转换它的原因。出于某种原因,当我这样做时

(MongoDBRepository<MerchantConfigurationEntity>)dataAccess.Object

我收到错误

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

我应该如何设置 Mock 然后传入对象,我尝试将变量设置为 dataAccess.Object 并传入该变量,但如果我这样做,设置将作为 null

下面是单元测试:

[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);
}

出于这个原因,您的 类 应该依赖于抽象而不是具体化。 MerchantConfigurationRepository 应该依赖于 IRepository<MerchantConfigurationEntity> 而不是实现 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) { ... }
}

这样一来,您现在可以更灵活地在隔离测试时使用模拟存储库。

var merchantRepo = new MerchantConfigurationRepository(dataAccess.Object);

只需确保您的 DI 知道在生产中使用实际实现即可。