最小起订量与 Unity 容器单元测试

Moq with Unity Container unit testing

下面是我尝试进行单元测试的生产代码示例。我正在努力解决对正在使用的具体 class 的依赖。

public MyClass(IUnityContainer container)
{
    this.unityContainer = container;
}

public string DoWork()
{
     var sender = unityContainer.Resolve<IInterface>();  // how to setup this object
     var json = sender.Send("something");
     var value = serializer.Deserialize<SomeModel>(json);
     return value.url;
}

我想模拟此方法使用的 IInterface。我如何在我的单元测试代码中设置它?我觉得这里缺少一些东西。这有一种反模式的味道......

这是 "service locator" antipattern,您可以在其中将依赖项注入容器/控制反转注入到您的逻辑中。

你应该传递它所依赖的IInterface,这样你就可以控制它可以获取哪些实例。参见 Dependency Injection container in constructor

如果无法重构 class,则必须在单元测试中注入容器。将容器设置为 return IInterface 的一个实例(或者更确切地说,一个模拟)。像这样:

public void MyUnitTest()
{
    IUnityContainer myContainer = new UnityContainer();
    myContainer.RegisterType<IInterface, YourInstance>();

    MyClass classUnderTest = new MyClass(myContainer);
    classUnderTest.DoWork();
    
    Assert...
}

请参阅 How to use Unity.RegisterType with Moq? 以模拟 YourInstance

我同意 CodeCaster。典型的模式是在构造函数中接受类型为 IInterface 的参数,并将其分配给 class 级变量。

public MyClass(IInterface sender)
{
    this.sender = sender;
}

测试时,只需传入您的最小起订量即可。 也就是说,有时我不喜欢通过构造函数传递依赖项。如:

  • 我可能需要 class
  • 的多个实例
  • 对象只是有条件地需要。
  • class 的构造函数可能依赖于直到 运行 时间才确定的其他值。

在那些情况下,将容器作为参数传递是我遇到的唯一解决方案。只需确保将容器的初始实例注册到自身即可。否则,DI 将为您的构造函数提供一个新的(空)容器。如果有人有更好的模式,尤其是与 Unity 一起使用的模式,我很乐意看到它。