我有以下代码
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从类中移出到另一个测试
提前致谢。
答案 0 :(得分:2)
您不想测试MethodA
和MethodB
之间的互动,您要测试MethodA
是否会返回预期bool
结果,给出一些背景。
MethodA
调用MethodB
的事实与此测试不是密切相关的;但Rep.GetResult()
在某些时候会被调用的事实是。
正如您所提到的,您可以模拟依赖项Rep
,因此MethodB
是public
还是private
无关紧要。
MethodA
答案 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作为示例模拟框架。