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

Per*_*erk 4 c# xunit .net-core

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

我遇到的问题是我想测试的一些方法是'私有'方法.如何在不使其范围"公开"的情况下从我的测试项目中调用这些方法?

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


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

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

Pat*_*ald 17

快速解决方案是让private您想要测试的成员internal.

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

例如

[assembly: InternalVisibleTo("Library.Tests")]
Run Code Online (Sandbox Code Playgroud)

  • 据我所知,您实际上可以将该属性放在项目源代码中的任何位置。AssemblyInfo.cs 没有什么特别的(除了约定)。 (6认同)
  • 而且,如果您没有AssemblyInfo.cs文件(从.NET Core 2.1开始,似乎没有自动生成一个文件),则可以创建一个文件,只需在上面添加一行,便会被选中。在您的测试项目中。 (2认同)

Toh*_*hid 7

对于测试内部类,@Patric 的答案是正确的。

据说,私有方法是私有的,这是有充分理由的。他们不应该成为内部的,这也是有充分理由的。

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

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

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}!";
  }
}
Run Code Online (Sandbox Code Playgroud)

测试是这样的:

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");
   }
 }
Run Code Online (Sandbox Code Playgroud)

参考:

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

  • 尽管您应该警告这不是一个好的做法,甚至在某些情况下,有点冒险。经验法则应该是“对公共方法进行测试” (2认同)