多亏了 Mock,如何避免 xunit.net 中的基调用方法
How to avoid base called method in xunit.net thanks to Mock
我正在尝试为我的 CutomSmtpMailer 编写单元测试代码。我的 CutomSmtpMailer 继承自 SmtpClient。
这是我的 class 的样子:
public class CutomSmtpMailer : SmtpClient
{
private void SendMail(MailMessage mailMessage)
{
//DoSomeStuff
Send(mailMessage); //base.Send(mailMessage)
}
}
我想在不发送邮件的情况下测试我的自定义代码:我想通过用空操作替换它来避免调用 "Send(mailMessage)",不知道它是否已被调用。当我使用 DI 时,我知道如何模拟一个实例,但我不想注入 SMTP 客户端(事实上我有很多继承的案例,这里是一个简单的例子)
public class TestCutomSmtpMailer
{
public CutomSmtpMailer Get()
{
return new CutomSmtpMailer();
}
[Fact]
public void SendMail()
{
CutomSmtpMailer service = Get();
MailMessage mailMessage = new MailMessage();
// Find on web but not available :(
Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
service.SendMail(mailMessage);
}
}
如何通过空函数 replace/Mock Parent class 方法来避免发送邮件?
提前致谢
因为您不想使用 依赖注入 来注入 SmtpClient
,您可以采用丑陋的方式添加一个 内部 构造函数并委托给 CustomSmtpMailer
以帮助模拟和测试。
请注意,这种方法不是很干净。
这将导致在您的产品装配中产生纯粹用于测试的代码,这通常不是一个好主意。
然而,它确实解决了您所描述的问题,让您不必使用 依赖注入。
public class CustomSmtpMailer : SmtpClient {
internal delegate void SendInternal(MailMessage message);
private SendInternal _sendAction;
// make sure all your constructors call this one.
// this will make the call to base.Send(MailMessage) the default behaviour.
public CustomSmtpMailer() {
_sendAction = delegate (MailMessage message) { Send(message); };
}
// customizes the SendMail(MailMessage) behaviour for testing purposes.
internal CustomSmtpMailer(SendInternal sendAction) {
_sendAction = sendAction;
}
private void SendMail(MailMessage mailMessage) {
//DoSomeStuff
_sendAction(mailMessage);
}
}
通过将其添加到项目中的 AssemblyInfo.cs
,使内部成员对您的测试项目可见。
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("My.Test.Assembly.Name")]
在您的单元测试中,您可以使用内部构造函数来配置碱基调用。
[Fact]
public void SendMail() {
CustomSmtpMailer service = new CustomSmtpMailer(delegate (MailMessage message) {
Console.WriteLine("I'm a custom Action that can be used for testing");
});
MailMessage mailMessage = new MailMessage();
// Find on web but not available :(
Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
service.SendMail(mailMessage);
}
我正在尝试为我的 CutomSmtpMailer 编写单元测试代码。我的 CutomSmtpMailer 继承自 SmtpClient。
这是我的 class 的样子:
public class CutomSmtpMailer : SmtpClient
{
private void SendMail(MailMessage mailMessage)
{
//DoSomeStuff
Send(mailMessage); //base.Send(mailMessage)
}
}
我想在不发送邮件的情况下测试我的自定义代码:我想通过用空操作替换它来避免调用 "Send(mailMessage)",不知道它是否已被调用。当我使用 DI 时,我知道如何模拟一个实例,但我不想注入 SMTP 客户端(事实上我有很多继承的案例,这里是一个简单的例子)
public class TestCutomSmtpMailer
{
public CutomSmtpMailer Get()
{
return new CutomSmtpMailer();
}
[Fact]
public void SendMail()
{
CutomSmtpMailer service = Get();
MailMessage mailMessage = new MailMessage();
// Find on web but not available :(
Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
service.SendMail(mailMessage);
}
}
如何通过空函数 replace/Mock Parent class 方法来避免发送邮件?
提前致谢
因为您不想使用 依赖注入 来注入 SmtpClient
,您可以采用丑陋的方式添加一个 内部 构造函数并委托给 CustomSmtpMailer
以帮助模拟和测试。
请注意,这种方法不是很干净。
这将导致在您的产品装配中产生纯粹用于测试的代码,这通常不是一个好主意。
然而,它确实解决了您所描述的问题,让您不必使用 依赖注入。
public class CustomSmtpMailer : SmtpClient {
internal delegate void SendInternal(MailMessage message);
private SendInternal _sendAction;
// make sure all your constructors call this one.
// this will make the call to base.Send(MailMessage) the default behaviour.
public CustomSmtpMailer() {
_sendAction = delegate (MailMessage message) { Send(message); };
}
// customizes the SendMail(MailMessage) behaviour for testing purposes.
internal CustomSmtpMailer(SendInternal sendAction) {
_sendAction = sendAction;
}
private void SendMail(MailMessage mailMessage) {
//DoSomeStuff
_sendAction(mailMessage);
}
}
通过将其添加到项目中的 AssemblyInfo.cs
,使内部成员对您的测试项目可见。
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("My.Test.Assembly.Name")]
在您的单元测试中,您可以使用内部构造函数来配置碱基调用。
[Fact]
public void SendMail() {
CustomSmtpMailer service = new CustomSmtpMailer(delegate (MailMessage message) {
Console.WriteLine("I'm a custom Action that can be used for testing");
});
MailMessage mailMessage = new MailMessage();
// Find on web but not available :(
Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
service.SendMail(mailMessage);
}