假设我已经编写了一个单元测试来测试XUnit中的公共方法。
[Fact]
public void MethodA_WhenSomething_ThenReturnNull()
{
// Code removed for brevity.
// Assert
}
这是MethodA。
public void MethodA() {
MethodOne();
MethodTwo();
MethodThree();
}
MethodOne、MethodTwo和MethodTree都是私有方法。在为MethodA运行单元测试时,有没有办法跳过私有方法(即MethodTwo(?我想跳过methodTwo的原因是methodTwo调用了一个存储过程,并导致Xuit出错。但我知道存储过程运行良好,没有问题,所以我可以跳过这个方法。
现在,我正在用这种方式。
public void MethodA() {
MethodOne();
#if DEBUG == false
MethodTwo();
#endif
MethodThree();
}
如果有更好的方法,我不想放If DEBUG
这类问题通常通过Moq.Protected
解决。
因此,至少对于MethodTwo
,您需要将private
访问器更改为protected
但我建议将所有访问者更改为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();
参考文献:
- 嘲笑受保护的成员
- 受保护的成员-C中的单元测试#
- Moq-如何用无参数构造函数模拟内部类的受保护方法
如果您的私有方法依赖于某个外部服务,那么您可以创建一个mock并将其标记为可验证。
[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库。
假设有以下类:
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包。因此,我们只需从源中复制三个文件:Extension.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();
}
其方法将用作替代的辅助类
public class Fake
{
static void Redirect() { }
}