良好的软件设计模式,用于单元测试的构造函数重载



我正在用 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

通过这种方式,您可以轻松控制在调用某个方法时获得模拟服务的值。

最新更新