[英]How should I test this?
I have a ViewModel, which when initialized, creates a list of objects. 我有一个ViewModel,它在初始化时会创建一个对象列表。 These objects are created by resolving interface implementation from IoC. 这些对象是通过解决IoC的接口实现而创建的。
ViewModel 视图模型
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);
}
}
Unit Test 单元测试
[TestClass]
public class ApplicanceViewModelTest
{
[TestMethod]
public void TestSomething()
{
//Arrange
var appliance = new ApplianceViewModel(); //This would fail to construct
}
}
The above initialization would fail as the kernel
would be null. 由于kernel
为空,因此上述初始化将失败。 Basically, it tells me that having a constant class and accessing kernel directly is a bad design. 基本上,它告诉我拥有一个常量类并直接访问内核是一个糟糕的设计。
But then how would I modify my viewmodel
's constructor so that I can initialize a list, in other words make it testable? 但是,然后我将如何修改viewmodel
的构造函数,以便初始化列表,换句话说,使其可测试?
Thank you. 谢谢。
But then how would I modify my viewmodel's constructor so that I can initialize a list, in other words make it testable? 但是然后我将如何修改我的viewmodel的构造函数,以便可以初始化列表,换句话说,使其可测试?
You inject it with implementations of the IHardware interface: 您将其与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);
}
}
So at runtime you could inject the view model with your existing constants: 因此,在运行时,您可以使用现有常量注入视图模型:
var appliance = new ApplianceViewModel(Constants.Kernel.Get<IHardware>(), Constants.Kernel.Get<IHardware>());
...and in your unit test project you pass in some other implemenation of the same interface: ...并且在您的单元测试项目中,您传递了相同接口的其他实现:
IHardware testHardware = new TestHardware();
var appliance = new ApplianceViewModel(testHardware, testHardware);
You will need to implement this "TestHardware" class in a way that makes your test pass. 您将需要通过使您的测试通过的方式来实现此“ TestHardware”类。 Using a mocking framework will be useful. 使用模拟框架将很有用。 Please refer to the following link for more information about this: http://codetunnel.io/what-is-a-mocking-framework-why-is-it-useful/ 请参考以下链接以获取有关此的更多信息: http : //codetunnel.io/what-is-a-mocking-framework-why-is-it-useful/
You can have another interface, ie IHardwareStuff
, that will return a list of IHardware
objects. 您可以具有另一个接口,即IHardwareStuff
,该接口将返回IHardware
对象的列表。 The IHardwareStuff
gets passed as an argument into the constructor of your ViewModel. IHardwareStuff
作为参数传递给ViewModel的构造函数。 It's resolved by the dependency injection container and you can input a test implementation when you want to. 它由依赖项注入容器解决,您可以在需要时输入测试实现。
By doing this separation, you split your object into a value object and a service object . 通过这种分离,您可以将您的对象分为一个值对象和一个服务对象 。 The first one you create by doing new
and passing some concrete values to it. 通过执行new
并将一些具体值传递给它来创建第一个。 The latter is created by the dependency injection container and doesn't have concrete values passed into it as a constructor. 后者是由依赖项注入容器创建的,没有作为构造函数传递给它的具体值。
You can than write unit tests for both objects. 然后,您可以为两个对象编写单元测试。
For a good and testable design it's better if constructors do nothing, validation or variable assignment. 对于良好且可测试的设计,最好让构造函数不执行任何操作,验证或变量分配。
I suggesto to inject in the constructor of ApplianceViewModel
the list HardwareItems
. 我建议在ApplianceViewModel
的构造函数中注入HardwareItems
列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.