如何使用IGenericRepository进行模拟

时间:2017-08-04 09:46:01

标签: c# unit-testing justmock

我是TDD开发的新手,我刚开始用Nunit 3.7.1,Newtonsoft.Json版本= 10.0.3,JustMock Lite版本2016.2.426.1,C#和.NET进行一些测试框架4.7。

我想测试这个课程:

public class LoadFinishedTrzlBatch
{
    private IGenericRepository<ProductionOrder> proOrdRepository;
    private IGenericRepository<Batch> batchRepository;
    private IGenericRepository<Code> codeRepository;
    private IGenericRepository<Aggregation> aggregationRepository;
    private IGenericRepository<AggregationChildren> aggChildrenRepository;

    public LoadFinishedTrzlBatch(
        IGenericRepository<ProductionOrder> proOrdRepository,
        IGenericRepository<Batch> batchRepository,
        IGenericRepository<Code> codeRepository,
        IGenericRepository<Aggregation> aggregationRepository,
        IGenericRepository<AggregationChildren> aggChildrenRepository)
    {
        this.proOrdRepository = proOrdRepository;
        this.batchRepository = batchRepository;
        this.codeRepository = codeRepository;
        this.aggregationRepository = aggregationRepository;
        this.aggChildrenRepository = aggChildrenRepository;
    }

    public bool ExistsProductionOrder(string productionOrderName)
    {
        if (string.IsNullOrWhiteSpace(productionOrderName))
            throw new ArgumentNullException(nameof(productionOrderName));

        return (
            proOrdRepository
                .SearchFor(p => p.Name == productionOrderName)
                .FirstOrDefault() != null
        );
    }
}

通过这个测试:

[TestFixture]
class LoadFinishedTrzlBatchTest
{
    private LoadFinishedTrzlBatch _load;

    [SetUp]
    public void SetUpLoadFinishedTrzlBatch()
    {
        var proOrdRepository = 
            Mock.Create<IGenericRepository<ProductionOrder>>();
        var batchRepository =
            Mock.Create<IGenericRepository<Batch>>();
        var codeRepository =
            Mock.Create<IGenericRepository<Code>>();
        var aggRepository =
            Mock.Create<IGenericRepository<Aggregation>>();
        var aggChildrenRepository =
            Mock.Create<IGenericRepository<AggregationChildren>>();

        _load = new LoadFinishedTrzlBatch(
            proOrdRepository,
            batchRepository,
            codeRepository,
            aggRepository,
            aggChildrenRepository);
    }

    [Test]
    public void ShouldExistsProductionOrder()
    {
        // Arrange
        Mock.Arrange(() => _load.ExistsProductionOrder("ProOrd"))
            .Returns(true)
            .MustBeCalled();

        // Act
        var actual = _load.ExistsProductionOrder("ProOrd");

        // Assert
        Assert.AreEqual(actual, true);
    }
}

最后这是IGenericRepository

public interface IGenericRepository<TEntity>
{
    [ OMITTED ]

    IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate);

    [ OMITTED ]
}

首先,我不确定这是否是测试方法LoadFinishedTrzlBatch.ExistsProductionOrder的正确方法。对于TDD而言,一切都是新的,我迷失了。

我对如何模仿IGenericRepository<ProductionOrder>感到困惑。它始终是真的,我没有测试IGenericRepository<ProductionOrder>。也许是因为我没有测试存储库。

我在学习,但我不知道自己在做什么。这就是我提出这个问题的原因。我想测试ExistsProductionOrder方法。

如何测试ExistsProductionOrder方法?

2 个答案:

答案 0 :(得分:1)

实际上,如果方法ExistsProductionOrder做了它应该做的事情,你想要测试。因此你不应该模仿它。但是,您希望模拟在 方法中名为的成员,例如对IGenericRepository<T>.DoSomething()的任何调用。

然而,只需调用它并将其结果与您期望的结果进行比较:

[Test]
public void ShouldExistsProductionOrder()
{
    // Act
    var actual = _load.ExistsProductionOrder("ProOrd");
    Assert.IsTrue(actual);
}

现在你的方法看起来像这样:

bool ExistsProductionOrder() {
    this.proOrdRepository.DoSomething();
    return ...
}

你可以将对 DoSomething 的调用替换为不同的东西 - 你的模拟。

答案 1 :(得分:1)

You need to separate the target dependency so that it can be arranged in isolation in the test case. You also do no mock the SUT (Subject under test). You mock its dependencies. In this case you want to mock the generic repository and arrange the method being called. ie SearchFor

Assuming that method takes a expression predicate, you can arrange the mock to expect one and then apply it to a fake collection store to mock an actual data store.

[TestFixture]
public class LoadFinishedTrzlBatchTest {
    private LoadFinishedTrzlBatch sut;
    //need this later so declaring as field.
    private IGenericRepository<ProductionOrder> proOrdRepository;

    [SetUp]
    public void SetUpLoadFinishedTrzlBatch() {  
        //Not using these so they can be declared locally          
        var batchRepository =
            Mock.Create<IGenericRepository<Batch>>();
        var codeRepository =
            Mock.Create<IGenericRepository<Code>>();
        var aggRepository =
            Mock.Create<IGenericRepository<Aggregation>>();
        var aggChildrenRepository =
            Mock.Create<IGenericRepository<AggregationChildren>>();

        //initializing target mock
        proOrdRepository = 
            Mock.Create<IGenericRepository<ProductionOrder>>();

        sut = new LoadFinishedTrzlBatch(
            proOrdRepository,
            batchRepository,
            codeRepository,
            aggRepository,
            aggChildrenRepository);
    }

    [Test]
    public void ShouldExistsProductionOrder()
    {
        // Arrange
        var productionOrderName = "ProOrd";
        var orders = new List<ProductionOrder>() {
            new ProductionOrder { Name = productionOrderName },
            new ProductionOrder { Name = "Dummy for Filter" }
        };
        Mock.Arrange(() => proOrdRepository
            .SearchFor(Arg.IsAny<Expression<Func<ProductionOrder,bool>>>()))
            .Returns((Expression<Func<ProductionOrder,bool>> expression) => 
                orders.Where(expression.Compile()).AsQueryable()
            )
            .MustBeCalled();

        // Act
        var actual = sut.ExistsProductionOrder(productionOrderName);

        // Assert
        Assert.IsTrue(actual);
    }
}