【问题标题】:How should I test this?我应该如何测试这个?
【发布时间】:2016-12-12 22:53:52
【问题描述】:

我有一个 ViewModel,它在初始化时会创建一个对象列表。这些对象是通过从 IoC 解析接口实现来创建的。

视图模型

    public class ApplianceViewModel : IAppliance
    {
        private List<IHardware> HardwareItems {get; set;}

        public ApplianceViewModel()
        {
            HardwareItems = new List<IHardware>();
            var hardware1 = Constants.Kernel.Get<IHardware>();
            var hardware2 = Constants.Kernel.Get<IHardware>();

            HardwareItems.Add(hardware1);
            HardwareItems.Add(hardware2);           
        }
    }

单元测试

[TestClass]
public class ApplicanceViewModelTest
{
    [TestMethod]
    public void TestSomething()
    {
        //Arrange
        var appliance = new ApplianceViewModel(); //This would fail to construct

    }
}

上述初始化将失败,因为kernel 将为空。基本上,它告诉我拥有一个常量类并直接访问内核是一个糟糕的设计。

但是我将如何修改我的viewmodel 的构造函数以便我可以初始化一个列表,换句话说,使它可测试?

谢谢。

【问题讨论】:

  • 将 IoC 与 DI 结合使用而不是 service locator anti pattern 会更好吗?
  • @SomeUser:是的,我认为 ServiceLocator 模式对我造成了伤害,但我心中的问题是如何重写它?然后我找到了this solution,我认为这可以解决我遇到的问题。

标签: c# wpf unit-testing mvvm ninject


【解决方案1】:

但是我将如何修改我的视图模型的构造函数以便我可以初始化一个列表,换句话说,使它可测试?

您将其注入 IHardware 接口的实现:

public class ApplianceViewModel : IAppliance
{
    private List<IHardware> HardwareItems {get; set;}

    public ApplianceViewModel(IHardware hardware1, Hardware hardware2)
    {
        HardwareItems = new List<IHardware>();
        var hardware1 = hardware1;
        var hardware2 = hardware2;

        HardwareItems.Add(hardware1);
        HardwareItems.Add(hardware2);           
    }
}

因此,在运行时,您可以使用现有常量注入视图模型:

var appliance = new ApplianceViewModel(Constants.Kernel.Get<IHardware>(), Constants.Kernel.Get<IHardware>());

...在您的单元测试项目中,您传递了同一接口的其他一些实现:

IHardware testHardware = new TestHardware();
var appliance = new ApplianceViewModel(testHardware, testHardware);

您需要以使您的测试通过的方式实现这个“TestHardware”类。使用模拟框架将很有用。请参考以下链接了解更多信息:http://codetunnel.io/what-is-a-mocking-framework-why-is-it-useful/

【讨论】:

  • 感谢您的详细说明。我有点知道该怎么做,但不知道怎么做。我想this 会帮我做我需要做的事情。
【解决方案2】:

您可以有另一个接口,即IHardwareStuff,它将返回IHardware 对象的列表。 IHardwareStuff 作为参数传递到 ViewModel 的构造函数中。它由依赖注入容器解决,您可以根据需要输入测试实现。

通过这种分离,您将对象拆分为一个值对象和一个服务对象。您通过执行new 并向其传递一些具体值来创建第一个。后者由依赖注入容器创建,并没有作为构造函数传递给它的具体值。

您可以为这两个对象编写单元测试。

【讨论】:

    【解决方案3】:

    对于良好且可测试的设计,构造函数最好什么都不做,验证或变量赋值。

    我建议在ApplianceViewModel的构造函数中注入列表HardwareItems

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多