首页 > 解决方案 > 使用 MS Fakes C# 的类中的单元测试静态方法

问题描述

这是我要模拟的课程。具有静态方法的助手类。这需要一个数据表。

public class DataTableHelpers
    {
        public static ArrayList GetDataTableColumns(DataTable dataTable)
        {
            if (dataTable == null)
            {
                throw new ArgumentNullException(nameof(dataTable));
            }

            var columnsCount = dataTable.Columns.Count;
            var columnHeadings = new ArrayList();
            for (var i = 0; i < columnsCount; i++)
            {
                var dataColumn = dataTable.Columns[i];
                columnHeadings.Add(dataColumn.ColumnName.ToString());
            }
            return columnHeadings;
        }
    }

尝试使用 ShimsContext。这是我想出的片段。想要在数据表为空且不为空时进行模拟。

public void GivenDatatableIsNUllShouldThrowNullException()
        {
            var expected = new ArrayList();
            //ARRANGE
            using (ShimsContext.Create())
            {
                dataTableHelpers = new DataTableHelpers();

                //ACT

                var result = ShimDataTableHelpers.GetDataTableColumnsDataTable = (s) =>
                {
                    Should.Throw<ArgumentNullException>(() =>
                    {
                    });
                    throw new ArgumentNullException(nameof(s));
                };
                //Assert

                Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreNotEqual(result, expected);
            }
        }

标签: c#asp.net.nettestingmicrosoft-fakes

解决方案


您的问题有点不清楚,但我认为您所追求的是一种测试使用给定静态辅助方法的代码的方法。测试静态助手很容易,测试使用这些助手的代码并不容易。当您遇到类似的事情时,我发现最好重构该代码以不使用静态助手。而是将该代码推入一个您可以抽象并注入到您需要它的地方的类中。但有时说起来容易做起来难。

作为权宜之计,您可以通过引入一个类来保存实际代码,然后在测试时将其换出,从而逐步转向该方向。这不使用 MS Fakes,但它是一种技术,可用于帮助使您的代码更具可测试性。

对不起,我不记得是谁首先提出了这种方法,当然不是我。但这里的想法:

创建一个类来保存逻辑:

public class DataTableHelperImpl : IDataTableHelperImpl
{
    public ArrayList GetDataTableColumns(DataTable dataTable)
    {
        if (dataTable == null)
        {
            throw new ArgumentNullException(nameof(dataTable));
        }

        var columnsCount = dataTable.Columns.Count;
        var columnHeadings = new ArrayList();
        for (var i = 0; i < columnsCount; i++)
        {
            var dataColumn = dataTable.Columns[i];
            columnHeadings.Add(dataColumn.ColumnName.ToString());
        }
        return columnHeadings;
    }
}

使用您可以模拟的关联接口:

public interface IDataTableHelperImpl
{
    public ArrayList GetDataTableColumns(DataTable dataTable);
}

然后在你的静态助手中使用它:

public static class Helper
{
    public static IDataTableHelperImpl implementation = new DataTableHelperImpl();

    public static ArrayList GetDataTableColumns(DataTable dataTable)
    {
        return implementation.GetDataTableColumns(dataTable);
    }
}

现在在你的测试中,你可以换掉那个类来模拟你想要的任何行为。

    [Fact]
    public void Test1()
    {
        var implMock = Mock.Of<IDataTableHelperImpl>();

        Helper.implementation = implMock;

        // whatever you need to test...
    }

推荐阅读