我正在用 c# 开发一个 Windows 窗体应用程序。实例化窗体时,我在构造函数中初始化了一些硬件类。 hardware1, Hardware2, Hardware3
表示我在软件中实例化的硬件类。
public partial class Form1 {
Hardware1 a;
Hardware2 b;
Hardware3 c;
public Form1() {
// initialize hardware1,2 and 3 using native dll calls of a,b and c
}
我想在我的主窗体中对此方法进行单元测试。
public int MyMethod(int percent, ref double power) {
for(int i =0; i<3; i++)
{
if(a.isValid)
{
b.DoThing1(percent);
b.DoThing2(true);
c.DoSomething1();
double val = C.DoSomething2();
if (val != -500)
{
power = val;
return 0;
}
}
else
return 1;
}
return 2;
}
困难在于a.IsValid是通过一些我必须模拟的dll调用设置的。 b.DoThing1和C.DoThing2也调用了一些我也必须模拟的dll函数。一种可能性是重载表单方法构造函数。然后我可以模拟每个类 dll 的
Form1 (Hardware1 a, Hardware2 b, Hardware3 c) {
this.a = a;
this.b = b;
this.c = c;
}
或者我应该有硬件 1 a、硬件 2 b 和硬件 3 c 的接口吗?我读到通常最好有接口来替换具体类。
什么是单元测试 Form1 myMethod 的良好软件实践?
使用接口的最大优点是单元测试可以定义自己的接口实现,这允许单元测试在没有外部依赖项的情况下执行。
我建议你做的是从你的表单中删除你的MyMethod,并将其放入它自己的类中。 一般来说,将业务与演示分开总是一个好主意。
这是我的建议:
public interface IHardware1 { }
public interface IHardware2 { }
public interface IHardware3 { }
public class Hardware1 : IHardware1 { }
public class Hardware2 : IHardware2 { }
public class Hardware3 : IHardware3 { }
public class MyClass
{
private IHardware1 _a;
private IHardware2 _b;
private IHardware3 _c;
public MyClass( IHardware1 hardware1, IHardware2 hardware2, IHardware3 hardware3 )
{
_a = hardware1;
_b = hardware2;
_c = hardware3;
}
public int MyMethod( int percent, ref double power )
{
...
_b.DoThing1( percent );
_b.DoThing2( true );
_c.DoSomething1();
...
}
}
然后在您的表单(以及您的单元测试项目中(中,您只需使用:
MyClass _myClass = new MyClass( a, b, c);
_myClass.MyMethod( x, y );
我建议使用 NUnit 和 NSubstitute 在 C# 中进行单元测试。
当你说针对接口而不是实际实现进行测试更好时,你是对的。使用 NSubstitute,您可以模拟接口并设置在该接口中声明的所有方法的返回值:
//Test
var someType = Substitute.For<ISomeType>();
var someParameter = 42;
var someReturnValue = 1;
someType.SomeMethod(someParameter).Returns(someReturnValue);
var sut = new SomeClass(someType); //sut means system under test
var result = sut.AMethod();
//This would test positive as you set the return value of SomeMethod to 1
//in case it gets called with a value of 42
Assert.That(result, Is.EqualTo(someReturnValue));
//Test end
//This would be the class you want to unit test
public class SomeClass
{
private ISomeType someType;
public SomeClass(ISomeType someType)
{
this.someType = someType;
}
public int AMethod()
{
return someType.SomeMethod(42);
}
}
这里发生的情况是,您的测试模拟SomeType
并将其方法的返回值设置为 SomeMethod
如果它被调用参数为 42
1
。
通过这种方式,您可以轻松控制在调用某个方法时获得模拟服务的值。