因此,我们已经手动创建了一个自定义模拟类。 - 它适用于我们现有的测试,但我们也希望能够验证是否在其上调用了给定的方法(即mock.Verify
)。 - 我可以在我们的模拟类中为每个方法和属性添加一百个布尔值,以验证每个方法是否使用正确的参数调用,但这会变得非常丑陋和毛茸茸,最终不会有与使用Moq一样保真。
如果模拟类没有注入依赖项,我可以使用new Mock<MyMockObject>()
创建一个新的,并且一切都可以正常工作。 - 但它也有Unity自动注入的依赖项,因此在这种情况下,它会失败,并将这些属性保留为null。
有没有什么方法可以让两人一起玩得很好? - 告诉Moq使用Unity创建课程的任何方法? - 或者告诉Unity填充Moq创建的类的任何方式? - 我应该使用一个了解Unity的不同模拟库吗?
这是我想要开始工作的控制台应用示例;现在Bar
属性为null(因为Moq不知道我的统一容器):
public class Bar: IBar
{
public string Text { get; set; }
}
public class Foobar: IFoobar
{
public virtual string Foo { get; set; }
[Dependency]
public virtual IBar Bar { get; protected set; }
}
public class Program
{
public static void Main(string[] args)
{
using (var uc = new UnityContainer())
{
// Injected by specific unit test:
uc.RegisterInstance<IBar>(new Bar() { Text = "Hello World!" });
// This way works, but I can't verify if methods get called.
Console.WriteLine
(
uc.Resolve<Foobar>().Bar.Text
);
// This way I can verify if certain methods were called, but "Bar" will never be
// populated, so the following will throw a NullReferenceException.
Console.WriteLine
(
new Mock<Foobar>().Object.Bar.Text
);
}
}
}
修改
伙计们,请不要挂断Unity和Moq之间的互操作,或者单元测试理念。 - 显然这个代码和场景非常简单。 - 我一般都在询问如何让事情发挥作用。
如果它可以帮助你从这种情况中删除Unity并将这个问题视为Moq唯一的问题,那很好,那时问题是:
如果我有一个预先构建的模拟对象(它来自工厂,或魔法仙女,或者我的叔叔给了我,它没关系,我有一个现有的模拟对象):我该怎么办在现有对象实例周围创建一个Mock包装器来拦截对其进行的调用? (主要是,我想通过Verify关键字来验证是否使用某些参数调用了某些方法,或者调用了某些属性等等。)
因此,我想做new Mock<IFoo>()
之类的事情,而不是Mock.GetWrapper(existingFooInstance)
。 - 这可能吗? - 看起来曾经有过这样做的图书馆,但我所发现的似乎没有维护,也没有超级实用。
答案 0 :(得分:0)
那么你到底要测试的是什么?你的Foobar
课程?然后你应该模仿但这个类的一切。
如果你想在Bar属性上进行验证,你可以这样模仿它:
var barMock = new Mock<IBar>();
barMock.SetupGet(x => x.Text).Returns("Hello World");
uc.RegisterInstance<IBar>(barMock.Object);
之后,您可以检查barMock上是否有任何内容被调用:
barMock.VerifyGet(x => x.Text);
另一方面,如果你进行单元测试,你应该尽可能地隔离你的测试类,所以使用Unity实际创建它并不是最好的想法。在我们的环境中,我们通常会将所有内容注入到构造函数中,这样我们就可以在单元测试中创建Foobar对象而不需要任何“Unity Magic”。也许你可以考虑一下而不是使用[Dependency]
属性。
答案 1 :(得分:0)
首先,如果这是单元测试(从您的问题中不清楚),使用像Unity这样的DI容器是过度的 - 你应该只有1 真实的任何给定方案的类,其余通常应该是使用new
关键字创建的模拟或存根。
其次,构造函数注入应始终是注入依赖项的首选。例如,对于给定方案,您可以确保它们永远不会null
,这简化了使用字段/属性的代码。
public class Foobar: IFoobar
{
public FooBar(IBar bar)
{
// using a guard clause ensures your dependency can
// never be null.
if (bar == null)
throw new ArgumentNullException("bar");
this.Bar = bar;
}
public virtual string Foo { get; set; }
public virtual IBar Bar { get; private set; }
}
此外,IMO使用容器的内置属性(例如[Dependency]
)来注入属性是一个糟糕的选择,因为这意味着您的应用程序依赖于特定的DI容器。此外,属性注入仅应用于可选依赖项(即,如果应用程序为null,则应用程序将忽略这些依赖项)。因此,使用构造函数注入来获取所需的依赖项。如果它们是可选的,要么找到基于约定的注入依赖关系的方法,要么使用自定义属性(来自您的应用程序)来发出注入信号,您也可以将其用于测试。然后,您不需要让DI容器参与测试。
我建议你阅读这本书Dependency Injection in .NET。显然,如果你认为你的单元测试需要一个DI容器并且你认为使用构造函数注入在某种程度上更加困难,那么你做错了什么。财产注入。我不能告诉你到底出了什么问题,因为你的例子过于简单,并且没有证明为什么你认为你需要一个容器进行单元测试。
依赖注入是指使应用程序松散耦合,这通常涉及显着限制(和重构)应用程序设计,使其遵循DI模式。容器的使用是完全可选的。这样可以非常简单地将应用程序与DI容器组合在一起,并手动组合单元测试。实际上,将DI容器放入单元测试只会使您的测试更难以理解。