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

本文关键字:一类 方法 交互 单元测试 | 更新日期: 2023-09-27 18:26:25

我有以下代码

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,测试MethodAMethodB之间交互的最佳实践是什么?我想测试MethodA,就像测试MethodB一样,通过模拟数据库依赖关系Rep来测试,就像方法A有以下实现一样

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

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

单元测试综合服务方法

但它不适用于C#。

还有一个问题,如果MethodB是私有的,它对单元测试策略有什么影响吗?

更新:不希望更改类的结构。比如不将MethodB设置为虚拟的,或者将MethodB从类中移出到另一个测试中

提前谢谢。

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

您不想测试MethodAMethodB之间的交互,您想测试在给定一些上下文的情况下,MethodA将返回预期的bool结果。

CCD_ 5调用CCD_;但CCD_ 7将在某个时刻被调用的事实是

正如您所提到的,您可以模拟依赖关系Rep,因此MethodBpublic还是private并不重要。

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

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

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

我建议你使用一个嘲讽框架(smug,rhino-mocks,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());
}
[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作为一个示例嘲讽框架。