测试对象是否用正确的参数值实例化
本文关键字:参数 实例化 对象 是否 测试 | 更新日期: 2023-09-27 18:02:26
我正在用Moq和Nunit对c#代码进行单元测试,我想测试下面的简化方法。在单元测试方面,我认为我不应该检查foo值,因为FooClass可能会发生变化,随后在未来破坏我的测试。我至少能做的是验证一切都被初始化并被正确调用,也就是说,someContainer获得正确的值FooClass获得someContainer而不是其他MyContainer实例。我怎么做呢?这种(单元)测试方法正确吗?
public MyClass
{
...
public bool MyMethod(int a, int b, int c, out FooClass foo)
{
var someContainer = new MyContainer{
A = a,
B = b,
C = c
};
foo = new FooClass(someContainer,1,2,3);
...
return true;
}
...
}
你不能测试foo
得到someContainer
,因为someContainer
只能从方法内部访问。对该方法的适当测试是foo
在正确的位置包含a
, b
和c
,并且它包含一些MyContainer
对象。这将是FooClass
构造函数的单元测试,测试FooClass
对象是否包含正确的MyContainer
对象。
如果你的FooClass
要改变,那么你的MyMethod
可能也会改变,所以MyMethod
的任何测试也必须改变。它中断测试的事实是好的,因为这意味着你需要查看那个方法并确保这个方法做了你想要的,并且你正在测试它做了你想要的。你应该现在就为这个方法编写适当的测试,或者在FooClass
完成之前不要费心编写任何测试。
这种(单元)测试方法正确吗?
如果你想模拟出依赖关系,这样你就可以测试代码的特定单元(例如,在你的例子中MyClass
),那么你需要考虑将你的代码组合成负责不同职责的服务。在你的例子中,你的MyMethod
有几个职责:
- 新建
MyContainer
- 新建
FooClass
- 提供
MyContainer
实例来创建FooClass
。
为了满足您测试MyMethod
将特定的MyContainer
传递到FooClass
的愿望,您可以将职责1和2分离到新的类中。通常,在c#中,您将为这些类提供一个接口,并让MyClass
将每个接口作为依赖项。例如
public interface IFooClassProvider
{
FooClass CreateFooClass(MyContainer container, int d, int e, int f);
}
public interface IMyContainerProvider
{
MyContainer CreateMyContainer(int a, int b, int c);
}
public MyClass
{
private IMyContainerProvider _myContainerProvider;
private IFooClassProvider _fooClassProvider;
public MyClass(IMyContainerProvider myContainerProvider, IFooClassProvider fooClassProvider)
{
_myContainerProvider = myContainerProvider;
_fooClassProvider = fooClassProvider;
}
...
public bool MyMethod(int a, int b, int c, out FooClass foo)
{
var someContainer = _myContainerProvider.CreateMyContainer(a,b,c);
foo = _fooClassProvider.CreateFooClass(someContainer,1,2,3);
...
return true;
}
...
}
希望接口的"真实"实现是显而易见的。为了执行测试,您可以为每个接口创建模拟,例如new Mock<IFooclassProvider>()
,并将它们传递给MyClass
的构造函数。在单元测试中,您可以Setup
IMyContainerProvider
模拟来提供您在单元测试中创建的特定容器实例。然后您可以Verify
, IFooClassProvider
模拟的方法是用特定的容器调用的。
。
var mockFooClassProvider = new Mock<IFooClassProvider>();
var mockMyContainerProvider = new Mock<MyContainerProvider>();
var myKnownContainer = new MyContainer(...);
mockMyContainerProvider.Setup(m => m.CreateMyContainer(It.IsAny<int>, ...))
.Returns(myKnownContainer);
var myClass = new MyClass(mockMyContainerProvider.Object, mockFooClassProvider.Object);
FooClass fooClass;
myClass.MyMethod(..., out fooClass);
mockFooClassProvider.Verify(m => m.CreateFooClass(myKnownContainer, It.IsAny<int>(),...);
对于这样一个简单的情况,这个答案是极端的,但我认为问题中的例子是一些更复杂的代码的简化版本。这种方式的职责分离将代码迅速简化为可测试的短段。