用于从列表中保存项目的单元测试

本文关键字:项目 单元测试 保存 列表 用于 | 更新日期: 2023-09-27 17:50:52

我创建了一个购物篮,我需要为它做单元测试。他们都很好,直到我遇到了一个小问题,我做了一些添加到篮子的单元测试等等,但有一个选项,以保存在lst_Results中的所有内容到您选择的文本文件文件夹中。保存按钮的代码是:

private void btn_Save_Click(object sender, EventArgs e)
    {

        var FileSave = new SaveFileDialog();
        FileSave.Filter = "Text (*.txt)|*.txt";
        if (FileSave.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            using (var streamwriter = new StreamWriter(FileSave.FileName, false))
            foreach (var item in lst_Results.Items)
            streamwriter.Write(item.ToString() + Environment.NewLine);
            MessageBox.Show("Success");
        }
    }

那么对于实际的单元测试本身这是我目前所拥有的但我不确定目标和断言应该是什么

[TestMethod()]
    public void SaveItems()
    {
        Basket.Basket target = new Basket.Basket();
        string itemname = "Orange"; 
        int quantity = 5; 
        decimal price = 5; 
        target.AddProduct(itemname, quantity, price);

        string itemname2 = "Banana";
        int quantity2 = 5; 
        decimal price2 = 1;
        target.AddProduct(itemname2, quantity2, price2);
        target.???();
        Assert.???);
    }

用于从列表中保存项目的单元测试

(重新)考虑您想要测试的内容。您是想测试UI还是测试将数据写入流?

测试按钮是集成测试的一部分,在单元测试中不是微不足道的。

我建议首先将写流提取到它自己的方法中

internal static void WriteToStream(IEnumerable<Basket.Basket> items,string filename){
   using (var streamwriter = new StreamWriter(filename, false))
      foreach (var item in items){
           streamwriter.Write(item.ToString() + Environment.NewLine);
      }
    }
}
private void btn_Save_Click(object sender, EventArgs e)
    {
        var FileSave = new SaveFileDialog();
        FileSave.Filter = "Text (*.txt)|*.txt";
        if (FileSave.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
           WriteToStream(lst_Results.Items, FileSave.FileName);
            MessageBox.Show("Success");
        }
}

(标记为内部的方法,允许从保存测试的外部程序集访问)

现在您已经隔离了流部分。您可以使用临时文件进行测试,并在写入后通过回读来断言文件的内容与您期望的内容匹配。

这还不是最佳的。您现在依赖于文件系统,对于小的读/写,这应该不会妨碍太多。但是您可以添加另一个间接方法来改进测试。

考虑进一步重写(实际上是重构)WriteToStream()

internal static void WriteToStream(IEnumerable<Basket.Basket> items, Func<TextWriter> createStream){
   using (var streamwriter = createStream())
      foreach (var item in items){
           streamwriter.Write(item.ToString() + Environment.NewLine);
      }
    }
}
private void btn_Save_Click(object sender, EventArgs e)
    {
        var FileSave = new SaveFileDialog();
        FileSave.Filter = "Text (*.txt)|*.txt";
        if (FileSave.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
           WriteToStream(lst_Results.Items,() => new StreamWriter(FileSave.FileName, false));
            MessageBox.Show("Success");
        }
    }
}

现在您可以创建一个伪造的(模拟的)StreamWriter,在这个StreamWriter上您可以断言条目被写入 StreamWriter:您只需要确保数据被写入写入器,写入器如何以及何时将其写入磁盘与您无关。

class FakeStreamWriter : TextWriter{ //StreamWriter IS A TextWriter
    public bool HasWritten {get; private set;}
    public override void Write(string content){
        HasWritten = true;
    }
    //omitted other methods for brevity
}
[Fact]
public void ItemAreWrittenToStream(){
    var myFakedStreamWriter = new FakeStreamWriter();
    var items = new List<Basket.Basket>{ new Basket.Basket{...}} 
    FormX.WriteToStream(item, () => myFakedStreamWriter );
    Assert.True( myFakedStreamWriter.HasWritten );
}

保存(和加载,如果有的话)代码应该移动到Basket的方法中。btn_Save_Click中打开流并写入数据的代码将进入购物篮的save方法。然后你的测试代码可以调用target.Save("filename.ext");然后,assert应该测试所创建的文件是否符合您的期望。

如果您想要更复杂,并且避免必须做磁盘I/O,这在一些自动化测试环境中可能很重要,那么您可以让您的保存代码接受流作为目标,然后在您的测试代码中提供内存流而不是文件流。然后,测试代码可以检查内存流并一起绕过文件I/O。

在编写测试时,我个人的观点是,最困难的事情是确保你正在测试正确的东西。例如,您实际上并不需要测试FileStream和刷新到磁盘是否有效,因为这不是您的代码。你的代码是写流本身的东西,这就是你想要测试的东西。这就是为什么在测试保存时提供内存流是可以接受的,即使生产环境中的代码永远不会使用内存流。

这里的另一个有用的教训是,编写测试可以使您发现可能是OOP设计问题的地方。通常具有良好的面向对象原则的对象非常容易测试,如果它们不是,那可能是您的对象设计需要工作的线索。在本例中,将流编写代码移动到自己的方法中。

您的按钮单击事件处理程序做得太多了。这使得单元测试变得困难。我将按如下步骤进行:

从按钮单击事件处理程序中提取保存部分。例如,您将有一个这样的方法:

public void SaveItemsTo(String fileName, IEnumerable items){
    using (var streamwriter = new StreamWriter(fileName, false))
        foreach (var item in items){
            streamwriter.Write(item.ToString() + Environment.NewLine);
        }    
}

一旦完成,您可以轻松地测试从篮子中保存项目。您的单元测试只缺少用于保存的行(您现在可以通过调用提取的方法来完成)和断言文件已经创建(您也可以选择检查文件内容)。

YourClass.SaveItemsTo(yourfilename,Basket.Products);
Assert.IsTrue(File.Exists(yourfilename));

这显然只是给你一个想法的草稿。显然有很多可能的改进。你把保存项目的方法放在哪里完全取决于你。