需要文件数据的单元测试类?

时间:2018-11-15 03:00:56

标签: c# unit-testing mocking

我正在扩展我们的单元测试套件,并且遇到了一个特定的类,我试图弄清楚如何进行模拟。我有一个方法可以接受byte []数组作为参数。在理想情况下,此字节数组将始终是包含某种形式的PDF文件。然后,它从该pdf中提取所有表单字段并返回它们。

如何潜在地模拟依赖于文件数据的逻辑?我唯一真正的想法是将pdf包含在项目中,并使用IO读取测试文件,或者尝试动态生成pdf表单,然后提取这些字段。

这是PDF提取器的代码:

public class PdfFormExtractor : IDisposable
{
    private readonly PdfReader _pdfReader;
    private readonly MemoryStream _newPdf;
    private readonly PdfStamper _pdfStamper;

    public PdfFormExtractor(byte[] pdf)
    {
        _pdfReader = new PdfReader(pdf);
        _newPdf = new MemoryStream();
        _pdfStamper = new PdfStamper(_pdfReader, _newPdf);
    }

    public FormDto ExtractForm()
    {
        var pdfFormFields = _pdfStamper.AcroFields;
        var form = new FormDto()
        {
            Fields = pdfFormFields.Fields.Select(n => new FormFieldDto
            {
                Name = n.Key,
                Label = n.Key
            }).ToList()
        };

        return form;
    }

    #region IDisposable Support
    // disposable implementation
    #endregion
}

2 个答案:

答案 0 :(得分:1)

使用资源文件。

在Visual Studio中,只需在测试项目中创建一个资源文件,以包含要在测试中使用的所有文件。 打开resx,您将看到通常的字符串列表。但您不仅限于字符串:您可以在左上角的下拉菜单中选择“文件”,然后将文件拖放到resx文件中。
在执行此操作时,请注意粘贴的文件属性:您可以选择将文件解释为二进制文件(如用例所示,显示为byte [])或文本(编码格式,显示为字符串)。

然后,在您的测试中,您可以仅使用测试文件的内容引用强类型的Resource对象和强类型的byte []。

在测试复杂场景时,尤其是与足够智能的序列化器/反序列化器(如Json.NET)配对使用时,此策略有很多应用。

您可以将任何复杂的数据结构序列化为Json,然后在测试中将其引用为字符串(直接由Resource文件的类公开),使用简单的JsonConvert.DeserializeObject反序列化并在业务逻辑上运行测试直接。

答案 1 :(得分:0)

您可以使用Microsoft.Fakes为* .dll生成假程序集。借助Fakes,我们可以弯曲任何属性,方法等的结果。

我伪造了Sqlconnection类,通常会对其进行模拟强化。

  1. 右键单击您的程序集(在本例中为 System.Data
  2. 创建假货程序集
  3. 它将创建shimsstubs
  4. 我们需要使用(ShimsContext.Create())添加范围。示波器中的所有内容都将按照您的建议进行操作。

    public void ExtractFormTest()
    {
    using (ShimsContext.Create())
    {
        #region FakeIt
        System.Data.SqlClient.Fakes.ShimSqlConnection.AllInstances.Open = (SqlConnection sqlConnection) =>
        {
            Console.WriteLine("Opened a session with Virtual Sql Server");
        };
    
        System.Data.SqlClient.Fakes.ShimSqlConnection.AllInstances.Close = (SqlConnection sqlConnection) =>
        {
            Console.WriteLine("Closed the session with Virtual Sql Server");
        };
    
        System.Data.SqlClient.Fakes.ShimSqlCommand.AllInstances.ExecuteNonQuery = (SqlCommand sqlCommand) =>
        {
            if (sqlCommand.CommandText.ToLower().Contains("truncate table"))
            {
                Console.WriteLine("Ran " + sqlCommand.CommandText + " at Virtual Sql Server");
                return 1;
            }
    
            return 0;
        };
    
        System.Data.SqlClient.Fakes.ShimSqlBulkCopy.AllInstances.WriteToServerDataTable = (SqlBulkCopy sqlBulkCopy, DataTable datatable) =>
        {
            Console.WriteLine("Written #" + datatable.Rows.Count + " records to Virtual Sql Server");
        };
    
        System.Data.Common.Fakes.ShimDbDataAdapter.AllInstances.FillDataSet = (DbDataAdapter dbDataAdapter, DataSet dataSet) =>
        {
            var _dataSet = new DataSet();
            var _dataTable = DataTableHelper.LoadFlatfileIntoDataTable(Path.Combine(dailyEmailFlatfilesDirectory, "Flatfile.txt"), flatfileDelimiter, flatfileDataTableFields, regexPatternMdmValidEmail, traceWriter);
            if (dbDataAdapter.SelectCommand.CommandText.Equals(mdmSqlStorProcForSpFlatfileData))
            {
                while (_dataTable.Rows.Count > 1000)
                    _dataTable.Rows.RemoveAt(0);
            }
            else if (dbDataAdapter.SelectCommand.CommandText.Equals(mdmSqlStorProcForStFlatfileData))
            {
                while (_dataTable.Rows.Count > 72)
                    _dataTable.Rows.RemoveAt(0);
            }
    
            dataSet.Tables.Add(_dataTable);
            dataSet = _dataSet;
            return 1;
        };
        #endregion
    
        #region Act
        FormDto formDto = ExtractForm();
        #endregion
    
        #region Assert
        // Upto the scope of your method and acceptance criteria
        #endregion
    }
    

    }

希望这会有所帮助!