如何避免或跳过 XUnit 测试的一些私有方法?
How to avoid or skip some private method for XUnit test?
假设我编写了一个单元测试来测试 XUnit 中的 public 方法。
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
// Code removed for brevity.
// Assert
}
这是方法 A。
public void MethodA() {
MethodOne();
MethodTwo();
MethodThree();
}
MethodOne、MethodTwo、MethodTree都是私有方法。有没有办法在 运行 我对 MethodA 进行单元测试时跳过私有方法(即 MethodTwo)?我想跳过 methodTwo 的原因是因为 methodTwo 调用存储过程并导致 Xunit 出错。但是我知道存储过程 运行 没问题,所以我可以跳过这个方法。
而现在,我正在使用这种方式。
public void MethodA() {
MethodOne();
#if DEBUG == false
MethodTwo();
#endif
MethodThree();
}
如果有更好的方法,希望不放If DEBUG
如果您的私有方法依赖于某些外部服务,那么您可以创建它的模拟并将其标记为可验证。
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
var barService = new Mock<Bar>();
barService.Setup(x => x.DoSomething()).Verifiable();
///
}
public class Foo
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodThree() => System.Console.WriteLine();
private void MethodTwo() => new Bar().DoSomething();
private void MethodOne() => System.Console.WriteLine();
}
public class Bar
{
public void DoSomething() => System.Console.WriteLine("....");
}
您可以使用多种方法来替换私有方法。让我们使用 MethodRedirect 库。
假设有以下 class:
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodOne() { }
private void MethodTwo() =>
throw new NotImplementedException();
private void MethodThree() { }
}
var sc = new SomeClass();
sc.MethodA(); // An exception will be thrown here.
以上库没有nuget包。因此,我们简单地从sources复制三个文件:Extensions.cs、MethodOperation.cs、MethodToken.cs.
然后编写如下单元测试:
[Fact]
public void MethodA_WhenCalled_NotThrow()
{
var sut = new SomeClass();
var fake = new Fake();
MethodInfo privateMethod = sut.GetType().GetMethod("MethodTwo", BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo redirectMethod = fake.GetType().GetMethod("Redirect", BindingFlags.Static | BindingFlags.NonPublic);
var token = privateMethod.RedirectTo(redirectMethod);
sut.MethodA(); // should not throw
token.Restore();
}
辅助class其方法将被用作替代
public class Fake
{
static void Redirect() { }
}
这类问题通常通过Moq.Protected
解决。
因此,您至少需要将 private
访问器更改为 protected
MethodTwo
。
但我建议将所有访问器更改为 protected
.
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
protected void MethodOne() { ... }
protected void MethodTwo() { ... }
protected void MethodThree() { ... }
}
这样,模拟设置将如下所示:
using Moq.Protected;
...
var mockSomeClass = new Mock<SomeClass>();
mockSomeClass.Protected()
.Setup("MethodTwo")
.Verifiable();
另外你可以设置一个Callback
来写出测试输出
const string toBeMockedMethodName = "MethodTwo";
mockSomeClass.Protected()
.Setup(toBeMockedMethodName)
.Callback(() => TestContext.Progress.Writeline($"{toBeMockedMethodName} has been called."))
.Verifiable();
参考文献:
假设我编写了一个单元测试来测试 XUnit 中的 public 方法。
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
// Code removed for brevity.
// Assert
}
这是方法 A。
public void MethodA() {
MethodOne();
MethodTwo();
MethodThree();
}
MethodOne、MethodTwo、MethodTree都是私有方法。有没有办法在 运行 我对 MethodA 进行单元测试时跳过私有方法(即 MethodTwo)?我想跳过 methodTwo 的原因是因为 methodTwo 调用存储过程并导致 Xunit 出错。但是我知道存储过程 运行 没问题,所以我可以跳过这个方法。
而现在,我正在使用这种方式。
public void MethodA() {
MethodOne();
#if DEBUG == false
MethodTwo();
#endif
MethodThree();
}
如果有更好的方法,希望不放If DEBUG
如果您的私有方法依赖于某些外部服务,那么您可以创建它的模拟并将其标记为可验证。
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
var barService = new Mock<Bar>();
barService.Setup(x => x.DoSomething()).Verifiable();
///
}
public class Foo
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodThree() => System.Console.WriteLine();
private void MethodTwo() => new Bar().DoSomething();
private void MethodOne() => System.Console.WriteLine();
}
public class Bar
{
public void DoSomething() => System.Console.WriteLine("....");
}
您可以使用多种方法来替换私有方法。让我们使用 MethodRedirect 库。
假设有以下 class:
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
private void MethodOne() { }
private void MethodTwo() =>
throw new NotImplementedException();
private void MethodThree() { }
}
var sc = new SomeClass();
sc.MethodA(); // An exception will be thrown here.
以上库没有nuget包。因此,我们简单地从sources复制三个文件:Extensions.cs、MethodOperation.cs、MethodToken.cs.
然后编写如下单元测试:
[Fact]
public void MethodA_WhenCalled_NotThrow()
{
var sut = new SomeClass();
var fake = new Fake();
MethodInfo privateMethod = sut.GetType().GetMethod("MethodTwo", BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo redirectMethod = fake.GetType().GetMethod("Redirect", BindingFlags.Static | BindingFlags.NonPublic);
var token = privateMethod.RedirectTo(redirectMethod);
sut.MethodA(); // should not throw
token.Restore();
}
辅助class其方法将被用作替代
public class Fake
{
static void Redirect() { }
}
这类问题通常通过Moq.Protected
解决。
因此,您至少需要将 private
访问器更改为 protected
MethodTwo
。
但我建议将所有访问器更改为 protected
.
public class SomeClass
{
public void MethodA()
{
MethodOne();
MethodTwo();
MethodThree();
}
protected void MethodOne() { ... }
protected void MethodTwo() { ... }
protected void MethodThree() { ... }
}
这样,模拟设置将如下所示:
using Moq.Protected;
...
var mockSomeClass = new Mock<SomeClass>();
mockSomeClass.Protected()
.Setup("MethodTwo")
.Verifiable();
另外你可以设置一个Callback
来写出测试输出
const string toBeMockedMethodName = "MethodTwo";
mockSomeClass.Protected()
.Setup(toBeMockedMethodName)
.Callback(() => TestContext.Progress.Writeline($"{toBeMockedMethodName} has been called."))
.Verifiable();
参考文献: