模拟一个具体类方法的返回值



我有一个这样的抽象工厂。

public abstract class AbstractFactory
{
    public abstract ISyncService GetSyncService(EntityType entityType);
}

我有它的具体实现,像这样

public class SyncFactory : AbstractFactory
{
    private readonly IOperatorRepository _operatorRepository;
    public SyncFactory( IOperatorRepository operatorRepository)
    {
        _operatorRepository = operatorRepository;
    }
    public override ISyncService GetSyncService(EntityType entityType)
    {            
            return new OperatorSyncService(_operatorRepository);           
    }
}

这个具体工厂的访问方法是这样的。

public void MethodTobeTested()
{
    var syncService =
                new SyncFactory(_operatorRepository).GetSyncService(entityType);
}

现在我需要为methodtobetesting()编写一个单元测试。

我像这样模拟GetSyncService()的返回值。但它调用的是实际的OperatorSyncService,而不是模拟。我需要这个模拟来模拟OperatorSyncService

中的另一个方法
private Mock<SyncFactory> _syncServiceMock;
_syncServiceMock = new Mock<SyncFactory>();
_syncServiceMock.Setup(m => m.GetSyncService(operator)).Returns(_operatorSyncServiceMock.Object);

有什么办法解决这个问题吗?

在你的SyncFactory实现中注入一个IOperatorRepository的实例。这很好,因为它允许你在需要的时候注入不同的版本,并为你创建一个IOperatorRepository的模拟实现。

您还创建了一个抽象工厂,看起来不错,但看起来问题在于您对工厂的使用;

var syncService =
            new SyncFactory(_operatorRepository).GetSyncService(entityType);

在你的methodtobetesting中,你创建了一个SyncFactory的具体实现,这使得抽象工厂有点多余,因为你不能注入不同的实现。我不知道你从哪里得到你的_operatorRepository实例,但我可以看到两种前进的方式。

  1. 包含MethodToBeTested类的构造函数中添加一个参数,需要你的抽象工厂的一个实例,然后让你MethodToBeTested使用这个注入工厂而不是创建一个新的,这将让你模拟整个工厂,这是我推荐的方法,因为类包含MethodToBeTested将不再需要知道如何创建一个工厂实例,它不应该如果你遵循单一职责原则。

  2. 和上面一样,而是注入IOperatorRepository而不是工厂,然后你可以注入一个模拟IOperatorRepository,但我不建议这样做,因为你已经完成了创建所有抽象的好工作,然后把这个工作放在一边,"新建"一个syncFactory实例并创建一个具体的依赖

MethodToBeTestedSyncFactory紧密耦合,因为该方法正在手动创建SyncFactory的新实例。这使得模拟依赖非常困难。

假设

public class ClassToBeTested {
    public void MethodTobeTested() {
        var syncService = new SyncFactory(_operatorRepository).GetSyncService(entityType);
        //...other code
    }
}

ClassToBeTested应该重构为

public class ClassToBeTested {
    private readonly AbstractFactory syncFactory;
    public ClassToBeTested (AbstractFactory factory) {
        this.syncFactory = factory
    }
    public void MethodTobeTested() {
        var syncService = syncFactory.GetSyncService(entityType);
        //...other code
    }
}

这将允许将依赖项模拟并注入到要测试的类中,并由要测试的方法访问。现在要测试的类只需要知道它需要知道的内容。它现在不再需要知道IOperatorRepository

方法MethodTobeTested中的new创建新实例,因此不能注入mock。注入工厂,例如作为参数,以便在测试中模拟它。

public void MethodTobeTested(AbstractFactory factory)
{
    EntityType entityType = null;
    var syncService = factory.GetSyncService(entityType);
}
[TestMethod]
public void Method_Condition_Result()
{
    // Arrange
    TestedClass tested = new TestedClass();
    Mock<ISyncService> syncServiceMock = new Mock<ISyncService>();
    Mock<AbstractFactory> factoryMock = new Mock<AbstractFactory>();
    factoryMock.Setup(f => f.GetSyncService(It.IsAny<EntityType>())).Returns(syncServiceMock.Object);
    // Act
    tested.MethodTobeTested(factoryMock.Object);
    // Assert
    // ...
}

相关内容

  • 没有找到相关文章

最新更新