Reputation: 283
I'm trying to code unit test for my CutomSmtpMailer. My CutomSmtpMailer inherit from SmtpClient.
Here is how my class looks like :
public class CutomSmtpMailer : SmtpClient
{
private void SendMail(MailMessage mailMessage)
{
//DoSomeStuff
Send(mailMessage); //base.Send(mailMessage)
}
}
I would like to test my custom code without sending mail : I want to avoid the call of "Send(mailMessage)" by replacing it by an empty Action, not knowing if it has been called. I knew how to mock an instance when i use DI, but i don't want to inject the SMTPclient (in fact i've numberous case with inheritence here is a simple exemple)
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);
}
}
How to replace/Mock the Parent class method by an empty func to avoid sending mail ?
Thanks in advance
Upvotes: 0
Views: 248
Reputation: 858
Since you don't want to inject the SmtpClient
using dependency injection, you could go the ugly way and add an internal constructor and delegate to CustomSmtpMailer
to aid in mocking and testing.
Please be aware that this approach is not very clean.
It will result in having code that is purely for testing in your product assembly which is usually not a good idea.
It does however solve your problem as described and gets you around having to use dependency injection.
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);
}
}
Make the internal members visible to your test project by adding this to your AssemblyInfo.cs
in your project.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("My.Test.Assembly.Name")]
In your unit test you can use the internal constructor to configure the base call.
[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);
}
Upvotes: 1