问题
I want to use it to fake System.Net.Mail.SmtpClient
in a MS-Test UnitTest. Therefor I added a Fakes Assembmly of System.dll. Then I create a ShimsContext
and a StubSmtpClient
.
using (ShimsContext.Create())
{
StubSmtpClient client = new StubSmtpClient();
}
But what do I do with it?
The ultimate goal would be to write a Test which expects that the send Method is called with a object of MailMessage
.
回答1:
You can create an interface which will expose functions that will be used from SmtpClient
public interface ISmtpClient
{
void Send(MailMessage mailMessage);
}
Then create your Concrete class which will do real job.
public class SmtpClientWrapper : ISmtpClient
{
public SmtpClient SmtpClient { get; set; }
public SmtpClientWrapper(string host, int port)
{
SmtpClient = new SmtpClient(host, port);
}
public void Send(MailMessage mailMessage)
{
SmtpClient.Send(mailMessage);
}
}
In your test method now you can mock it and use like;
[TestMethod()]
public void SendTest()
{
Mock<ISmtpClient> smtpClient = new Mock<ISmtpClient>();
SmtpProvider smtpProvider = new SmtpProvider(smtpClient.Object);
string @from = "from@from.com";
string to = "to@to.com";
bool send = smtpProvider.Send(@from, to);
Assert.IsTrue(send);
}
回答2:
This isn't really an answer to your question, but an alternative aproach:
In the app.config, set up the smtp settings to deliver the mails as files to a local directory instead. Then you can load the file and check the contents in your assert section.
You'll have to write a bit more code for the assertion (or preferably create some helper functions) but you won't have to do anything that affects the production code.
回答3:
Another alternative is to use nDumbster:
Install-Package nDumbster
It runs an Smtp server in memory, which you can then verify against. It turns it more into an integration test, but generally those are higher value than unit tests, as you want to test the SmtpClient
usage is also correct.
回答4:
A version of this answer by Teoman shipahi that correctly disposes of the SmtpClient
.
First make ISmtpClient
inherit IDisposable
:
public interface ISmtpClient : IDisposable
{
void Send(MailMessage mailMessage);
}
Then implement IDisposable
in the SmtpClientWrapper
class:
public class SmtpClientWrapper : ISmtpClient
{
private bool disposed;
private readonly SmtpClient smtpClient;
public SmtpClientWrapper(string host, int port)
{
smtpClient = new SmtpClient(host, port);
}
~SmtpClientWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
smtpClient?.Dispose();
}
disposed = true;
}
}
protected void CheckDisposed()
{
if (disposed)
{
throw new ObjectDisposedException(nameof(SmtpClientWrapper));
}
}
public void Send(MailMessage mailMessage)
{
CheckDisposed();
smtpClient.Send(mailMessage);
}
}
For this version of SmtpClientWrapper
, I have removed the SmtpClient
property to avoid the problem of the SmtpClient
objects not being disposed of when replaced in setter of the SmtpClient
property.
来源:https://stackoverflow.com/questions/19971364/how-to-mock-fake-smtpclient-in-a-unittest