简体   繁体   English

C#-测试通用私有函数

[英]c# - test generic private function

I have a class with a private function that dozens of other public functions use. 我有一个带有私有函数的类,其他许多公共函数都使用它。

This private function just wrap other private functions that call to third party with try-catch 此私有函数只是包装其他通过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 ...
        }
    }

I want to test this wrap function to be sure it catches all exceptions correctly, but I don't like to test it again for each public function that use it. 我想测试此wrap函数,以确保它正确捕获了所有异常,但是我不希望为使用它的每个公共函数再次对其进行测试。 (however, i want to verify they call to this function (like mock.Verify()) (但是,我想验证他们是否对此函数进行了调用(如模拟.Verify())

What is the best practice to deal with that? 处理该问题的最佳做法是什么?

One option is to extract the wrapped function to another class, but I am not sure it's good solution since the wrapped function usages and relevance are just in the current class. 一种选择是将包装的函数提取到另一个类,但是由于包装函数的用法和相关性仅在当前类中,因此我不确定这是一个好的解决方案。 thanks! 谢谢!

I think problem is in design. 我认为问题出在设计上。 You should test only public functionlity directly and private should be tested indirectly. 您应该只直接测试公共功能,而应该间接测试私有功能。 It is hard for me to say what is wrong using one wrapper function. 使用一个包装器函数很难说出什么错。 But I want to link this question , maybe it will help to refactore your part of code. 但是我想链接这个问题 ,也许它将有助于重构您的代码部分。 If you need mock.Verify() so use it:) Extract functionality to special class. 如果您需要ockock.Verify(),请使用它:)将功能提取到特殊类中。

I think that the best option is to change it to be protected and to have an inherited class with a wrapper function to this function. 我认为最好的选择是将其更改为受保护的对象,并使其具有带有该函数的包装器类的继承类。 this way the only change on your production code is the private function changed to protected and the new class can be part of your test project. 这样,对生产代码的唯一更改就是将私有功能更改为protected,并且新类可以成为测试项目的一部分。

An option is to make the method internal, then expose it to your test suite using the InternalsVisibleToAttribute allowing your test suites to view internal members of your class. 一种选择是使该方法成为内部方法,然后使用InternalsVisibleToAttribute将其公开给您的测试套件,以允许您的测试套件查看类的内部成员。

Add the following to AssemblyInfo.cs in your project, 将以下内容添加到项目中的AssemblyInfo.cs中,

[assembly: InternalsVisibleTo("mytestassembly)]

If your assembly is signed, it is a bit more work. 如果您的程序集已签名,则需要更多工作。 You need to also sign your test assembly and add the PublicKey of your test assembly to the attribute. 您还需要签名测试程序集,然后将测试程序集的PublicKey添加到属性中。 You can get the public key using sn.exe -Tp mytestassembly.dll from a Visual Studio Command Prompt, then add it to the attribute like this; 您可以从Visual Studio命令提示符中使用sn.exe -Tp mytestassembly.dll获取公用密钥,然后将其添加到属性中,如下所示:

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

You can also look at this answer for InternalsVisibleTo . 您也可以查看InternalsVisibleTo的答案。

You also don't mention anything about your Login() method. 您也没有提及有关Login()方法的任何内容。 I assume that you are using dependency injection to mock out the functionality in the login? 我假设您正在使用依赖注入来模拟登录中的功能?

I would suggest a refactor. 我建议重构。 Move the code that you want to test to separate class ExternalLibCaller and inject the caller object into main class. 将要测试的代码移动到单独的类ExternalLibCaller上,并将调用者对象注入到主类中。 Then you can create: 然后,您可以创建:

  • tests for ExternalLibCaller to test reactions for exceptions, 测试ExternalLibCaller以测试异常反应,

  • tests for main class with ExternalLibCallerMock to check if SafeCall was executed, 使用ExternalLibCallerMock对主类进行测试,以检查是否已执行SafeCall,

  • tests for main class with ExternalLibCaller to check whole external lib API. 使用ExternalLibCaller测试主类,以检查整个外部lib API。

Example: 例:

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 ...
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM