![]() |
Development Lifecycle »
Design and Architecture »
Unit Testing
License: The Code Project Open License (CPOL)
UnitTestContext - Use of a simple yet powerful way to unit test void methods using Mock ObjectsBy S. M. SOHANThis article presents a simple yet very handy way to write unit tests for void methods. |
|
||||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

UnitTestContext is a simple static class that can be used as a shared memory among different classes. A void method of a mock implementation [of an interface] may utilize this shared memory to have some sort of return mechanism at the same time as complying to the interface. Then, we can write assertions on the UnitTestContext to codify our assumptions though unit testing.
//A template method for all classes sending emails
///////////////////////////////////////////
//
//Template Method
//
///////////////////////////////////////////
// 1. Configure the Mail Message (to, cc, subject, body)
// 2. Create and add the attachment file
// 3. Configure the SmtpClient
// 4. Send the Message
// 5. Perform clean up
public virtual void Run()
{
try
{
System.Net.Mail.MailMessage message = createEmail(this.EmailAppType);
message = addAttachment(message);
ISMTPClient client = getSMTPClient(this.EmailAppType);
client.Send(message);
}
catch (Exception ex)
{
throw ex;
}
finally
{
OnRunCompleted();
}
}
public interface ISMTPClient
{
//the SMTPConfig Attribute
SMTPConfig SmtpConfig
{
get;
set;
}
//The Send method - yet another void method!
void Send(MailMessage message);
}
public class SMTPConfig
{
public SMTPConfig()
{
}
public SMTPConfig(int id, string name, string host, int port, string userName, string password, bool requiresSSL )
{
_smtpConfigID = id;
_smtpConfigName = name;
_host = host;
_port = port;
_userName = userName;
_password = password;
_requiresSSL = requiresSSL;
}
private int _smtpConfigID;
public int SMTPConfigID
{
get { return _smtpConfigID; }
set { _smtpConfigID = value; }
}
private string _smtpConfigName;
public string SMTPConfigName
{
get { return _smtpConfigName; }
set { _smtpConfigName = value; }
}
private string _host;
public string Host
{
get { return _host; }
set { _host = value; }
}
private int _port;
public int Port
{
get { return _port; }
set { _port = value; }
}
private string _userName;
public string UserName
{
get { return _userName; }
set { _userName = value; }
}
private string _password;
public string Password
{
get { return _password; }
set { _password = value; }
}
private bool _requiresSSL;
public bool RequiresSSL
{
get { return _requiresSSL; }
set { _requiresSSL = value; }
}
}
internal class SMTPEmailClient :ISMTPClient
{
private SMTPConfig _smtpConfig;
public SMTPConfig SmtpConfig
{
get { return _smtpConfig; }
set { _smtpConfig = value; }
}
private SmtpClient _smtpClient;
public SMTPEmailClient()
{
}
public SMTPEmailClient(SMTPConfig config)
{
_smtpConfig = config;
}
#region ISMTPClient Members
public void Send(System.Net.Mail.MailMessage message)
{
configureClient();
try
{
_smtpClient.Send(message);
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
private void configureClient()
{
if (_smtpConfig == null)
{
throw new Exception("Failed to configure SMTPClient. SmtpConfig is Null. Please provide appropriate value");
}
_smtpClient = new SmtpClient(_smtpConfig.Host, _smtpConfig.Port);
_smtpClient.EnableSsl = _smtpConfig.RequiresSSL;
NetworkCredential credential = new NetworkCredential(_smtpConfig.UserName, _smtpConfig.Password);
_smtpClient.Credentials = credential;
}
}
class MockSMTPClient : ISMTPClient
{
#region ISMTPClient Members
public void Send(System.Net.Mail.MailMessage message)
{
UnitTestContext.Current["Message"] = message;
}
#endregion
#region ISMTPClient Members
public VFSmoothie.Data.SMTPConfig SmtpConfig
{
get
{
return UnitTestContext.Current["SmtpConfig"];
}
set
{
UnitTestContext.Current["SmtpConfig"] = value;
}
}
#endregion
}
public static class UnitTestContext
{
public static Dictionary<string, object> Current;
static UnitTestContext()
{
Current = new Dictionary<string, object>();
}
public static void Reset()
{
Current = new Dictionary<string, object>();
}
}
private SomeEmailSender _sender = null;
[SetUp]
public void Init()
{
_sender = new SomeEmailSender();
//Assign the mock implementaion of the ISMTPClient
_sender.EmailClient = new MockSMTPClient();
//Start with an empty Unit Test Context
UnitTestContext.Reset();
}
[Test]
public void TestRun()
{
try
{
// This will hit MockSMTPClient's Send method
_sender.Run();
//Load the expected Test Data
EmailApp app = new EmailAppDAL().GetEmailApp(EmailAppType.SomeType);
SMTPConfig config = new SMTPConfigDAL().GetSMTPConfig(EmailAppType.SomeType);
List<EmailRecipient> toList = new EmailRecipientDAL().GetEmailRecipients(EmailAppType.SomeType, AddressType.To);
List<EmailRecipient> ccList = new EmailRecipientDAL().GetEmailRecipients(EmailAppType.SomeType, AddressType.CC);
//Make Assertions
MailMessage message = UnitTestContext.Current["Message"] as MailMessage;
Assert.AreEqual(app.FromEmail, message.From.Address);
Assert.AreEqual(app.FromName, message.From.DisplayName);
Assert.AreEqual(app.Subject, message.Subject);
Assert.AreEqual(app.Body, message.Body);
SMTPConfig smtpConfig = UnitTestContext.Current["SMTPConfig"] as SMTPConfig;
Assert.AreEqual(config.Host, smtpConfig.Host);
Assert.AreEqual(config.Port, smtpConfig.Port);
Assert.AreEqual(config.UserName, smtpConfig.UserName);
Assert.AreEqual(config.Password, smtpConfig.Password);
Assert.AreEqual(config.RequiresSSL, smtpConfig.RequiresSSL);
for(int i = 0; i < message.To.Count; i++)
{
Assert.AreEqual(message.To[i].Address, toList[i].EmailAddress);
}
for (int i = 0; i < message.CC.Count; i++)
{
Assert.AreEqual(message.CC[i].Address, ccList[i].EmailAddress);
}
}
catch (Exception)
{
Assert.Fail();
}
}
This way we can write unit tests for methods that seem unfit for regular unit testing directions. I hope this will be helpful for someone with similar needs.
Dependency Injection techniques must be used to actually write effective unit tests. And I have used 'Spring.Net' for
Implementing Dependency Injection. If you haven't yet taken a look at Dependency Injection and wondering about writing
unit tests, I must say, please take a look at this cool technique first.
As a disclaimer, I know there may be other good solutions to similar problem and in that case I will look forward to hear
from my readers.
| You must Sign In to use this message board. | |||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 7 Jan 2008 Editor: |
Copyright 2008 by S. M. SOHAN Everything else Copyright © CodeProject, 1999-2010 Web22 | Advertise on the Code Project |