.Net核心库:如何使用xUnit测试私有方法

时间:2017-01-04 11:14:27

标签: c# .net-core xunit

当使用.Net Core框架编译时,最新的xunit框架不允许库代码中的测试运行器(这适用于普通的Visual Studio代码)。解决方案是创建一个单独的测试项目来运行测试用例。

我遇到的问题是我想测试的一些方法是私有的'方法。 如何从我的测试项目中调用这些方法而不使其范围公开'公众

更一般的问题是:当使用私有方法的公共方法无法使用时,如何测试私有方法?(因为它具有交互性 - 也就是说,它有一个ReadLine ();包含在其中)

可能的解决方案:
1)将私有方法公开,并以某种方式重命名它们,以表明它们不应在外部使用。 (使用'私人'或'内部'作为名称的一部分)
2)创建一个' public static bool Testflag'可以设置为true的字段,以绕过公共方法的交互部分,以确保测试其所有部分。

(虽然我已经使用了上述两种方法 - 我真的不喜欢它,因为私有方法应该保持私有,而标志会增加许多额外的复杂性。有人遇到了同样的问题吗?你是怎么解决的?

4 个答案:

答案 0 :(得分:15)

快速解决方案是让private成员要测试internal

然后,您可以将InternalsVisibleTo属性添加到主库的AssemblyInfo.cs中。这将允许您的测试库(没有其他库,没有反射)访问主库中的内部方法/类。

e.g。

[assembly: InternalVisibleTo("Library.Tests")]

答案 1 :(得分:1)

对于测试内部类,@Patric's answer是正确的。

据说,私有方法是私有的,这有充分的理由。同样,它们也不应成为内部原因,这是有充分理由的。

(还有一些人认为我们不应该为私有方法编写单元测试。为什么?好吧,因为它们是“私有”的!但是如果您真的很认真地为私有方法编写单元测试:)

这是测试私有方法的更好方法:

public class Hello
{
  private string _firstName { get; set; }
  private string _lastName { get; set; }

  public Hello(string firstName, string lastName)
  {
     _firstName = firstName;
     _lastName = lastName;
  }

  public string HelloMan()
  {
    if (string.IsNullOrEmpty(_firstName))
       throw new Exception("Missing First Name.");
    return this.HelloMan(_firstName, _lastName);
  }

  private string HelloMan(string firstName, string lastName)
  {
     return $"Hello {firstName} {lastName}!";
  }
}

测试过程如下:

public class HelloTests
{
  [Fact]
   public void PrivateHelloManShouldBeWellFormated()
   {
      // Arrange
      var firstName = "John";
      var lastName = "Doe";

      Type type = typeof(Hello);
      var hello = Activator.CreateInstance(type, firstName, lastName);
      MethodInfo method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
      .Where(x => x.Name == "HelloMan" && x.IsPrivate)
      .First();

      //Act
      var helloMan = (string)method.Invoke(hello, new object [] {firstName, lastName});

     //Assert
     helloMan
     .Should()
     .StartWith("Hello")
     .And
     .EndWith("!")
     .And
     .Contain("John")
     .And
     .Contain("Doe");
   }
 }

参考:

http://anthonygiretti.com/2018/08/26/how-to-unit-test-private-methods-in-net-core-applications-even-if-its-bad/

答案 2 :(得分:1)

如果您需要测试私有方法,那么您就是代码异味。您应该检查您的体系结构,而没有理由要测试私有属性或方法。如果您需要此方法-它不是私有方法,而是另一个类的公共方法。

答案 3 :(得分:0)

老式的逐步改进使得对实用主义者(如果不是纯粹主义者)测试私有方法很有用。

将@Tohid最佳答案再进一步一步,该类可用于调用静态或实例私有方法

public static class TestPrivate
{
    public static T StaticMethod<T>(Type ClassType, string Method, object[] CallParams)
    {
        MethodInfo method = ClassType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
        .Where(x => x.Name == Method && x.IsPrivate)
        .First();

        T output = (T)method.Invoke(null, CallParams);

        return output;
    }

    public static T InstanceMethod<T>(object instance, string Method, object[] CallParams)
    {
        Type ClassType = instance.GetType();
        MethodInfo method = ClassType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
        .Where(x => x.Name == Method && x.IsPrivate)
        .First();

        T output = (T)method.Invoke(instance, CallParams);

        return output;
    }
}

然后按以下方式使用:

        {
            var result = TestPrivate.InstanceMethod<bool>(InstanceOfClass, "privateMethod", new object[] { param1, param2 });

            Assert.True(result);

            var actual = TestPrivate.StaticMethod<myReturnType>(typeof(StaticClass), "privateMethod", new object[] { param1, param2, param3 });

            Assert.True(actual.prop == expected.prop);
        }