C# 使用Moq对datatable导出服务进行单元测试

C# 使用Moq对datatable导出服务进行单元测试,c#,wpf,unit-testing,moq,C#,Wpf,Unit Testing,Moq,我有一个服务要导出为csv文件,该文件位于WPF应用程序的videmodel中: public void ExportToExcel() { DataTable tblFiltered = _currentTable.AsEnumerable() .Where(r => r.Field<string>("Type") == ExportGridGroup)

我有一个服务要导出为csv文件,该文件位于WPF应用程序的videmodel中:

 public void ExportToExcel()
    {

        DataTable tblFiltered = _currentTable.AsEnumerable()
                          .Where(r => r.Field<string>("Type") == ExportGridGroup)
                          .CopyToDataTable();

        StringBuilder sb = new StringBuilder();
        IEnumerable<string> columnNames = tblFiltered.Columns.Cast<DataColumn>().
                                          Select(column => column.ColumnName);
        sb.AppendLine(string.Join(",", columnNames));

        foreach (DataRow row in tblFiltered.Rows)
        {
            IEnumerable<string> fields = row.ItemArray.Select(field => "\"" + field.ToString() + "\"");
            sb.AppendLine(string.Join(",", fields));
        }

        String result = sb.ToString();
        try
        {
            StreamWriter sw = new StreamWriter("export.csv");
            sw.WriteLine(result);
            sw.Close();
            Process.Start("export.csv");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
public void ExportToExcel()
{
DataTable tblFiltered=\u currentTable.AsEnumerable()
其中(r=>r.Field(“Type”)==ExportGridGroup)
.CopyToDataTable();
StringBuilder sb=新的StringBuilder();
IEnumerable columnNames=tblFiltered.Columns.Cast()。
选择(column=>column.ColumnName);
sb.AppendLine(string.Join(“,”,columnNames));
foreach(tblFiltered.Rows中的数据行)
{
IEnumerable fields=row.ItemArray.Select(field=>“\”+field.ToString()+“\”);
sb.AppendLine(string.Join(“,”字段));
}
字符串结果=sb.ToString();
尝试
{
StreamWriter sw=新StreamWriter(“export.csv”);
软件写入线(结果);
sw.Close();
Process.Start(“export.csv”);
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
}
}
基于此,我为它创建了一个测试方法,但还没有完成

 [TestMethod()]
    public void ExportToExcelTest()
    {
        //Step 1: Creating a mock table with columns
        DataTable testtable = new DataTable();
        DataRow mydatarow;
        mydatarow = testtable.NewRow();
        //Step 2: Adding the row 
        mydatarow["ColumnA"] = "12345";
        mydatarow["ColumnB"] = "test";

        testtable.Rows.Add(mydatarow);

        StringBuilder sb = new StringBuilder();
        IEnumerable<string> columnNames = testtable.Columns.Cast<DataColumn>().
                                          Select(column => column.ColumnName);
        sb.AppendLine(string.Join(",", columnNames));

        foreach (DataRow row in testtable.Rows)
        {
            IEnumerable<string> fields = row.ItemArray.Select(field => "\"" + field.ToString() + "\"");
            sb.AppendLine(string.Join(",", fields));
        }

        String result = sb.ToString();
        StreamWriter sw = new StreamWriter("export.csv");
        sw.WriteLine(result);
        sw.Close();
        Process.Start("export.csv");          
        Assert.Fail();
    }
[TestMethod()]
公共无效ExportToExcelTest()
{
//步骤1:创建包含列的模拟表
DataTable testtable=新DataTable();
数据行mydatarow;
mydatarow=testtable.NewRow();
//步骤2:添加行
mydatarow[“ColumnA”]=“12345”;
mydatarow[“ColumnB”]=“测试”;
testtable.Rows.Add(mydatarow);
StringBuilder sb=新的StringBuilder();
IEnumerable columnNames=testtable.Columns.Cast()。
选择(column=>column.ColumnName);
sb.AppendLine(string.Join(“,”,columnNames));
foreach(testtable.Rows中的DataRow行)
{
IEnumerable fields=row.ItemArray.Select(field=>“\”+field.ToString()+“\”);
sb.AppendLine(string.Join(“,”字段));
}
字符串结果=sb.ToString();
StreamWriter sw=新StreamWriter(“export.csv”);
软件写入线(结果);
sw.Close();
Process.Start(“export.csv”);
Assert.Fail();
}
我有点困惑,因为在测试方法中,我几乎在项目中编写了完全相同的代码。。。。。
关于如何编写此单元测试以及有关WPF/C#单元测试的任何详细参考,我可以从Moq开始提供一些建议吗?

考虑将
try
块中的代码提取到另一个服务中

public interface ICsvWriter
{
    void WriteOutput(string text);
}
并将其作为依赖项传递给导出服务的构造函数

public Service(ICsvWriter csvWriter)
{
    this.csvWriter = csvWriter;
}
然后,您可以编写这样的测试来验证它是否实际输出了您期望的内容

[TestMethod]
public void TestMethod1()
{
    var csvWriter= new Mock<ICsvWriter>();
    var service = new Service(csvWriter.Object);
    string exportedText = string.Empty;

    // set up your mock so that whatatever string you pass in
    // gets passed to your exportedText variable.
    csvWriter.Setup(s => s.WriteOutput(It.IsAny<string>())).Callback<string>(s => exportedText = s);

    var testtable = new DataTable();
    // .... add test data

    // set the table on the view model
    service.SetData(testtable);

    // call the export method.
    service.ExportToExcel();

    // check that the result matches your expectation
    Assert.AreEqual("the text you expect to be written", exportedText);
}
更新

您还可以通过将
DataTable
作为参数传入,来提高导出方法的可测试性。然后,您可以在没有用于设置数据的公共属性的情况下对其进行测试

public void ExportToExcel(DataTable currentTable)
{
    DataTable tblFiltered = currentTable.AsEnumerable()
                          .Where(r => r.Field<string>("Type") == ExportGridGroup)
                          .CopyToDataTable();

    // ... 
}

考虑将
try
块中的代码提取到其他服务

public interface ICsvWriter
{
    void WriteOutput(string text);
}
并将其作为依赖项传递给导出服务的构造函数

public Service(ICsvWriter csvWriter)
{
    this.csvWriter = csvWriter;
}
然后,您可以编写这样的测试来验证它是否实际输出了您期望的内容

[TestMethod]
public void TestMethod1()
{
    var csvWriter= new Mock<ICsvWriter>();
    var service = new Service(csvWriter.Object);
    string exportedText = string.Empty;

    // set up your mock so that whatatever string you pass in
    // gets passed to your exportedText variable.
    csvWriter.Setup(s => s.WriteOutput(It.IsAny<string>())).Callback<string>(s => exportedText = s);

    var testtable = new DataTable();
    // .... add test data

    // set the table on the view model
    service.SetData(testtable);

    // call the export method.
    service.ExportToExcel();

    // check that the result matches your expectation
    Assert.AreEqual("the text you expect to be written", exportedText);
}
更新

您还可以通过将
DataTable
作为参数传入,来提高导出方法的可测试性。然后,您可以在没有用于设置数据的公共属性的情况下对其进行测试

public void ExportToExcel(DataTable currentTable)
{
    DataTable tblFiltered = currentTable.AsEnumerable()
                          .Where(r => r.Field<string>("Type") == ExportGridGroup)
                          .CopyToDataTable();

    // ... 
}

在测试的方法中有很多紧密耦合,我看不到在该方法中有效使用Moq的机会。考虑重构测试方法,依赖于服务抽象,使其在隔离中更可测试。单元测试应该执行一种方法并断言结果。因此,您应该调用
ExportToExcel
,而不是重新创建逻辑。然而,@Nikosi说了什么。这段代码实际上是不可测试的。在被测试的方法中有很多紧密耦合,我看不到有多少机会在该方法中有效地使用Moq。考虑重构测试方法,依赖于服务抽象,使其在隔离中更可测试。单元测试应该执行一种方法并断言结果。因此,您应该调用
ExportToExcel
,而不是重新创建逻辑。然而,@Nikosi说了什么。这段代码实际上是不可测试的。