只有当您想要测试需要所述依赖项的行为,但您不希望(或不能)实际创建该依赖项的“真实”实例时,才应使用模拟来创建假依赖项。任何包含多个模拟的测试方法都朝着错误的方向前进,因为这表明您有太多依赖项,或者您正在测试太多不相关的东西。
在您上面的代码中,没有依赖项,因此 Mocks 并不适合您真正需要的。
您确实需要考虑 究竟是您要在这里测试。为了争论,我们假设您显示的代码来自一个方法:
public class MyFooClass
{
public int DoFooFooData(FooAdapter Foo)
{
Data.Foo.FooDataTable tbl = Adapter.GetFooByID(id);
//just imagining what you might do here.
int total=0;
foreach (Data.Foo.FooRow row in tbl)
{
x = row.bar
//just imagining what you might do here.
total+=x;
}
return total;
}
}
为了测试DoFooFooData,我们需要做的是提供一个假的(Mock)FooAdapter,它只实现了GetFooByID 方法,以便您的函数能够执行。
为此,您必须将 FooAdapter 抽象化或(我建议)通过接口声明它:
public interface IFooAdapter
{
Data.Foo.FooDataTable GetByID(int id);
}
(稍后您需要更改 FooAdapter class 以实现 IFooAdapter,如果您想实际使用 DoFooFooData 方法)
现在更改您的方法签名:
public void DoFooFooData(IFooAdapter Foo)
{
Data.Foo.FooDataTable tbl = Adapter.GetFooByID(id);
int total=0;
foreach (Data.Foo.FooRow row in tbl)
{
x = row.bar
//just imagining what you might do here
total+=x;
}
return total;
}
最后在你的测试方法中,你可以模拟这个依赖:
void DoFooFooData_DoesSomeFooAndReturns3()
{
var mock = new Mock<IFooAdapter>();
var table = new Data.Foo.FooDataTable();
table.Add(new Data.Foo.FowRow{bar=1});
table.Add(new Data.Foo.FowRow{bar=2});
mock.Setup(m=>m.GetByID(It.IsAny<int>()).Returns(table);
var sut = new MyFooClass();
var expected=3;
var actual=sut.DoFooFooData(mock.Object);
Assert.AreEqual(expected,actual);
}
当然,如果您还需要模拟 FooDataTable,您可以遵循与 IFooAdapter 相同的模式,但您需要在这一点上停下来问问自己是否不应该创建一个 单独的测试,您在其中模拟 IFooDataTable 并确保它执行它应该做的事情(添加方法或其他)等等......当您确定 @ 的行为契约时987654338@ 可以,然后您可以将其实现为一个具体的“存根”,然后您可以在IFooAdapter 的上下文中使用它来代替任何FooDataTable 引用......但是现在您正在进入集成测试是另一天的故事......