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

时间:2014-03-19 11:36:17

标签: c# unit-testing testing

我已经创建了一个购物篮,我需要为它进行单元测试。它们一直很好,直到我遇到一个小问题,我已经完成了单元测试,以便在篮子中添加一些东西等等,但是有一个选项可以将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.???);

    }

3 个答案:

答案 0 :(得分:2)

(重新)考虑你想要测试的内容。您想测试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,你可以在其上声明项目被写入 a 编写器:你只需要确保将数据写入编写器,如何以及何时作者得到它到磁盘不是你的问题。

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 );
}

答案 1 :(得分:0)

保存(如果有的话,加载)代码可能应该转移到Basket上的方法中。 btn_Save_Click中打开流并写出数据的代码将进入购物篮的保存方法。然后你的测试代码可以调用target.Save(“filename.ext”);然后,您的断言应该测试创建的文件是否符合您的预期。

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

在编写测试时,我个人认为最难的事情就是确保你正在测试正确的东西。例如,你真的不需要测试FileStream并刷新到磁盘工作,因为那不是你的代码。你的代码是什么,是写入流本身的东西,这就是你想要测试的东西。这就是测试在测试保存时提供内存流的原因,即使生产设置中的代码永远不会使用内存流。

这里另一个有用的教训是,编写测试可以使您找到可能是OOP设计问题的内容。通常,具有良好OOP主体的对象非常容易测试,如果不是,那么可能是您的对象设计需要工作的线索。在这种情况下,将流写入代码移动到自己的方法中。

答案 2 :(得分:0)

您的按钮点击事件处理程序的功能超出了预期。这使得单元测试变得困难。我将按如下方式进行:

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

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));

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