如何对多个依赖项进行单元测试

时间:2019-09-30 08:39:32

标签: c# unit-testing dependency-injection

我想用C#(使用NUnit)编写一些单元测试,但是我不确定如何继续。

所以我有一个类,它提供一个具有四个属性的用户模型DataModel。我在ExcelInit构造函数中发送此模型。

DataModel dm = new DataModel();
dm.PopulateDataModel(holder);

ExcelInit d1 = new ExcelInit(dm);
d1.BeginProcess();

,然后在BeginProcess中启动我的实际方法。

public class ExcelInit
{
    public DataModel _model { get; set; }

    public ExcelInit(DataModel model)
    {
        _model = model;
    }

    public void BeginProcess()
    {
        DataReader dr = new DataReader();
        CellLocation cl = new CellLocation();
        //Gets the corresponding cellAddress for the cell that contains "2x5" from our hidden config-sheet
        var correspondingCellsAddress = cl.FindCorrespondingCellAddress(_model.boxSize);
        //returns the range that we need to copy i.e. the whole range of the box ala B3:AG13
        var srcRange = dr.GetRangeForSourceDestination(correspondingCellsAddress);
        //Last row of sheet 6 (the sheet we populate) with input-boxes
        var lastRow = dr.FindLastRowByName("Your_Data_Sheet") + 3;
        //gets the cell we'll copy our range to
        var destRange = "B" + lastRow.ToString();

        DataHandler dh = new DataHandler();
        dh.CopyBox(srcRange, destRange, _model);
    }

但是正如您所看到的,我在BeginProcess中创建了很多类,我的老师告诉我,我不能这样做(我需要使用DI才能进行测试)。但是我的问题是,当我需要在方法中使用这么多的类时,如何使用DI?还是我的方法不对,我不应该依赖太多不同的事物吗?

2 个答案:

答案 0 :(得分:1)

DI的目的不是避免创建实例。甚至DI容器也必须以某种方式创建依赖项的实例,例如通过反射。

DI大约在位置处创建那些实例。话虽如此,您不应该让被测系统(SuT,在您的情况下为类ExcelInit)创建自己的依赖项,而只是将它们注入到系统中,例如通过使用构造函数注入或仅将参数设置为您的方法:

public void BeginProcess(DataReader dr, CellLocation cl, DataHandler dh)
{
    //Gets the corresponding cellAddress for the cell that contains "2x5" from our hidden config-sheet
    var correspondingCellsAddress = cl.FindCorrespondingCellAddress(_model.boxSize);
    //returns the range that we need to copy i.e. the whole range of the box ala B3:AG13
    var srcRange = dr.GetRangeForSourceDestination(correspondingCellsAddress);
    //Last row of sheet 6 (the sheet we populate) with input-boxes
    var lastRow = dr.FindLastRowByName("Your_Data_Sheet") + 3;
    //gets the cell we'll copy our range to
    var destRange = "B" + lastRow.ToString();

    dh.CopyBox(srcRange, destRange, _model);
}

现在在您的测试中,您已经有了:

var target = new ExcelInit();
target.BeginProcess(new DataReader(), new CellLocation(), new DataHandler());

当然,这将执行完全相同的指令。但是,您现在也可以这样做:

var target = new ExcelInit();
target.BeginProcess(new SomeSpecificDataReader(), new CellLocation(), new DataHandler());

当您只是将阅读器注入而不是在SuT中创建阅读器时,实际的SuT根本就不会改变。因此,实际上您的被测系统并不依赖于特定的文件,而是依赖于数据。此数据的存储位置与您的BeginProcess方法无关。例如,您可以提供另一个excel文件(假设您的系统使用excel文件),一个xml文件或什至是一些内存中的数据存储。

答案 1 :(得分:0)

您的老师似乎使您感到困惑,并且可能使自己困惑。

如果依赖项由您控制,他的建议将起作用。那不是你的情况。您正在直接使用Excel的API,并且使用new注入您正在创建的类不会帮助您进行可测试性。如果您要遵循老师的建议,则必须为整个Excel的API创建测试倍数,我认为这是不可能的,因为该API并非为可测试性而设计。

遵循老师建议的一种方法是创建自己的包装Excel的API。考虑到可测试性,可以做到这一点。但是查看您的代码,我觉得这只会将问题向下推一层。您将使解决方案复杂化,而无需对真正重要的代码进行自动测试。

我建议您请老师给他举例说明他的意思。注入这些类将如何通过编写实际测试来提高代码的可测试性。我敢肯定,如果在您的方案中创建更多可测试的代码实际上没有帮助的话,他也会实现他的建议。