单元测试C#中同一类中方法的交互

时间:2012-03-02 22:25:33

标签: c# unit-testing mocking

我有以下代码

public ClassToTest : IClassToTest
{
    private readonly DBRepository rep;

    public bool MethodA()
    {
        //Some logic
        var result=MethodB();
        //Do some logic against result;
    }
    public ResultType MethodB()
    {
        return Rep.GetResult();
    }
}

如果我想进行单元测试 MethodA ,那么测试 MethodA MethodB 之间交互的最佳做法是什么?我想通过模拟数据库依赖 Rep 来测试 MethodA ,就像测试 MethodB 一样,就像 MethodA 具有以下实现一样

    public bool MethodA()
    {
        //Some logic
        var result=Rep.GetResult();
        //Do some logic against result;
    }

但通过检查代码和测试方法中的逻辑,这是不直观的。我正在寻找类似于这里提到的Java解决方案。

unit testing composite service methods

但它不适用于C#。

另外一个问题,如果 MethodB 是私有的,那么单元测试策略会有什么不同吗?

更新:不想改变类的结构。比如不将MethodB作为虚拟或将MethodB从类中移出到另一个测试

提前致谢。

3 个答案:

答案 0 :(得分:2)

您不想测试MethodAMethodB之间的互动,您要测试MethodA是否会返回预期bool结果,给出一些背景。

MethodA调用MethodB的事实与此测试不是密切相关的;但Rep.GetResult()在某些时候会被调用的事实是。

正如您所提到的,您可以模拟依赖项Rep,因此MethodBpublic还是private无关紧要。

  1. 模拟并注入依赖
  2. 致电MethodA
  3. 断言结果

答案 1 :(得分:0)

您想要隔离您测试的方法,也就是说,您希望在测试MethodA时模拟MethodB,反之亦然。

此外,还有一个测试范例来测试类的合同(或接口)。在这个范例中,您不必担心非公共非虚拟方法。我倾向于尽可能地嘲笑。

我建议你使用一个模拟框架(自鸣得意,犀牛模拟,moq,easymock)Smug是最酷的,但还没有完成 - 我只会告诉你下面的代码(这是如何工作没有一个模拟框架来帮助你。)

public enum ResultType
{
  Ok,
  NotOk,
}

public abstract class DBRepository
{
  public abstract ResultType GetResult();
}

public class ClassToTest
{
  public DBRepository Rep { get; set; }

  public virtual bool MethodA()
  {
    //Some logic
    var result = MethodB();
    //Do some logic against result;

    return result == ResultType.Ok;
  }

  protected virtual ResultType MethodB()
  {
    return Rep.GetResult();
  }
}

public class DBRepositoryMock : DBRepository
{
  public ResultType FakeReturn { get; set; }
  public override ResultType GetResult()
  {
    return FakeReturn;
  }
}

public class ClassToTest_MethodA : ClassToTest
{
  public ResultType MethodB_FakeReturn { get; set; }

  protected override ResultType MethodB()
  {
    return MethodB_FakeReturn;
  }
}

// tests

[TestMethod]
public void Test1()
{
  ClassToTest mock = new ClassToTest_MethodA();
  (mock as ClassToTest_MethodA).MethodB_FakeReturn = ResultType.Ok;
  Assert.IsTrue(mock.MethodA());
}

// or using injection
[TestMethod]
public static void Test2()
{
  var obj = new ClassToTest();
  obj.Rep = new DBRepositoryMock { FakeReturn = ResultType.NotOk };
  Assert.IsFalse(obj.MethodA());
}

答案 2 :(得分:0)

[TestMethod]
public void MethodAReturnsTrueGivenSomeDataAndCondition()
{
IDBRepository mockRepo = new Mock<IDBRepository>(); //Create a mock of your repository call
ClassToTest subjectToTest = new ClassToTest(mockRepo.Object); //Inject the dependency

mockRepo.SetUp(r=>r.GetResult()).Returns(someSampleTestData); //You're setting up the object that might return you true to return when mock repo will be called, by default it returns the default or null usually

var result = subjectToTest.MethodA();
mockRepo.Verify(r=>r.GetResult(), Times.Once); //Make sure your repo method was called
Assert.IsTrue(result); 

}

像这样,使用Moq作为示例模拟框架。