c# - 测试通用私有函数

时间:2016-02-09 07:25:32

标签: c# class unit-testing nunit moq

我有一个私有函数的类,有许多其他公共函数使用。

这个私有函数只包含使用try-catch调用第三方的其他私有函数

private T TryCatchCallWrapper<T>(Func<T> method)
    {
        try
        {
            Login();
            return method();
        }
        catch (ConnectionException e)
        {
            switch (e.ConnectionReason)
            {
                case ConnectionReasonEnum.Timeout:
                    throw new ...
            }
        }
        catch (XException e)
        {
            throw ...
        }
    }

我想测试这个包装函数,以确保它正确捕获所有异常,但我不想再为每个使用它的公共函数测试它。 (但是,我想验证他们调用此函数(如mock.Verify())

处理这个问题的最佳做法是什么?

一个选项是将包装函数提取到另一个类,但我不确定它是不是很好的解决方案,因为包装函数的用法和相关性只在当前类中。 谢谢!

4 个答案:

答案 0 :(得分:2)

我认为问题在于设计。您应该直接测试public functionlity,并且应该间接测试private。我很难用一个包装函数说出错误。但我想链接this question,也许它会有助于重构你的代码部分。如果你需要mock.Verify()所以使用它:)将功能提取到特殊类。

答案 1 :(得分:1)

我认为最好的选择是将其更改为受保护并使用包含该函数的包装函数的继承类。 这样,生产代码的唯一变化就是将私有函数更改为protected,新类可以成为测试项目的一部分。

答案 2 :(得分:1)

选项是将方法设为内部,然后使用InternalsVisibleToAttribute将其公开到测试套件,以允许测试套件查看您班级的内部成员。

将以下内容添加到项目中的AssemblyInfo.cs

[assembly: InternalsVisibleTo("mytestassembly)]

如果您的程序集已签名,则需要更多工作。您还需要对测试程序集进行签名,并将测试程序集的PublicKey添加到属性中。您可以从Visual Studio命令提示符中使用sn.exe -Tp mytestassembly.dll获取公钥,然后将其添加到此属性中;

[assembly: InternalsVisibleTo("mytestassembly, PublicKey=002400000480000094" +
                         "000000060200000024000052534131000400000100010031eea" +
                         "370b1984bfa6d1ea760e1ca6065cee41a1a279ca234933fe977" +
                         "a096222c0e14f9e5a17d5689305c6d7f1206a85a53c48ca0100" +
                         "80799d6eeef61c98abd18767827dc05daea6b6fbd2e868410d9" +
                         "bee5e972a004ddd692dec8fa404ba4591e847a8cf35de21c2d3" +
                          "723bc8d775a66b594adeb967537729fe2a446b548cd57a6")]

您还可以查看InternalsVisibleTo的答案。

您也没有提及有关Login()方法的任何内容。我假设你使用依赖注入来模拟登录中的功能?

答案 3 :(得分:1)

我会建议一个重构器。将要测试的代码移动到单独的ExternalLibCaller类,并将调用者对象注入主类。然后你可以创建:

  • 测试ExternalLibCaller以测试异常的反应,

  • 使用ExternalLibCallerMock测试主类以检查是否执行了SafeCall,

  • 使用ExternalLibCaller测试主类以检查整个外部lib API。

示例:

public class ClassWithPrivateTryCatchCallWrapper
{
    IExternalLibCaller externalLibCaller;

    public ClassWithPrivateTryCatchCallWrapper(IExternalLibCaller externalLibCaller)
    {
        this.externalLibCaller = externalLibCaller;
    }

    private T SafeCallWithLogin<T>(Func<T> method)
    {
        externalLibCaller.SafeCall(() =>
        {
            Login();
            return method();
        })
    }

    //use: SafeCallWithLogin(method)
    //insted: TryCatchCallWrapper(method);
}

public interface IExternalLibCaller
{
    T SafeCall<T>(Func<T> method)
}

public class ExternalLibCaller : IExternalLibCaller
{
    public T SafeCall<T>(Func<T> method)
    {
        try
        {
            return method();
        }
        catch (ConnectionException e)
        {
            switch (e.ConnectionReason)
            {
                case ConnectionReasonEnum.Timeout:
                    throw new ...
            }
        }
        catch (XException e)
        {
            throw ...
        }
    }
}