如何模拟采取措施的方法?

时间:2019-09-11 19:03:00

标签: c# mocking nunit

如何对DoWork方法进行单元测试?

public class SomeClass {
  private readonly IClass1 class1;
  private readonly Class2 class2;

  // IClass1 and Class2 are injected in ctor

  public string DoWork() {
    // do some work

    if(this.class2.Method2(() => this.class1.Method1())) {
      return "done!";
    }

    // other work 
  }

}

public interface IClass1 {
  void Method1();
}

public class Class2 {
  public virtual bool Method2(Action action) {
      // return true or false
  }
}

2 个答案:

答案 0 :(得分:1)

下面的示例使用MoqFluentAssertions来测试SomeClass.DoWork的测试用例,其中涉及Class2调用成员Method2并采取行动来调用{ {1}}

IClass1.Method1

理想情况下,[TestClass] public class SomeClassTests { [TestMethod] public void DoWork_Should_Be_Done() { //Arrange IClass1 class1 = Mock.Of<IClass1>(); Mock<Class2> class2 = new Mock<Class2>(); class2.Setup(_ => _.Method2(It.IsAny<Action>())) .Returns(true) .Callback((Action passedAction) => passedAction?.Invoke()); SomeClass subject = new SomeClass(class1, class2.Object); string expected = "done!"; //Act var actual = subject.DoWork(); //Assert actual.Should().Be(expected); //actual == expected Mock.Get(class1).Verify(_ => _.Method1(), Times.Once); //was action invoked } } 依赖关系应在接口后面抽象

Class2

但是这超出了原始问题的范围。

以上测试模拟了依赖关系及其预期行为。可以对该测试进行各种变化,以涵盖可以完全覆盖该方法的替代方案。

答案 1 :(得分:1)

从上面的代码中,我看到注入的IClass1仅用于作为注入的class2中的参数传递。这是代码的味道!!主类SomeClass不应该对Class1一无所知。 因此,我建议以一种使Class2了解Class1的方式重构代码

    public class SomeClass {
    private readonly IClass2 class2;

    public SomeClass(IClass2 class2)
    {
        this.class2 = class2;
    }

    // class1 and class2 are injected in ctor

    public string DoWork() {
        // do some work

        if(this.class2.Method2()) {
            return "done!";
        }

        // other work 

        return string.Empty;
    }

}

public interface IClass1 {
    void Method1();
}

public interface IClass2
{
    bool Method2();
}

public class Class2 : IClass2
{
    private IClass1 class1;

    public Class2(IClass1 class1)
    {
        this.class1 = class1;
    }

    public virtual bool Method2() {
        // return true or false
        class1.Method1();
        return true;
    }
}

然后您可以轻松对其进行测试。

       [Test]
    public void WhenMethod2ReturnTrue_ThenDoWork_ShouldReturn_Done()
    {
        Mock<IClass2> class2 = new Mock<IClass2>();
        SomeClass someClass = new SomeClass(class2.Object);

        class2.Setup(x => x.Method2()).Returns(true);

        var doWork = someClass.DoWork();

        Assert.That(doWork,Is.EqualTo("done!"));
    }

    [Test]
    public void WhenMethod2ReturnFalse_ThenDoWork_ShouldReturn_Empty()
    {
        Mock<IClass2> class2 = new Mock<IClass2>();
        SomeClass someClass = new SomeClass(class2.Object);

        class2.Setup(x => x.Method2()).Returns(false);

        var doWork = someClass.DoWork();

        Assert.That(doWork,Is.Empty);
    }

我已将Moq库用于模拟接口