Reputation: 439
I have a web application that sends an sms by consuming an ASMX service(which is now production and working fine), however I now need to unit test this application consumes the asmx service, below is the specific action method I'm interested in unit testing
public ActionResult CreateSms(SendSMSViewModel tblSend)
{
if (ModelState.IsValid)
{
if (_dbManager.SendSMS(tblSend.CellNumber, tblSend.Message, User.Identity.Name))
{
TempData["Success"] = "Message was successfully sent";
}
else
{
TempData["Error"] = "An error occured while sending the message";
}
}
return RedirectToAction("CreateSms");
}
So this action method receives a view model as parameter, this vmodel has 2 properties(cell number, message) and there is also user who is sending the sms. Now in my unit test or integration(apologies I also happen to confuse the two) I have the following code, this first part I am just trying to mock the method(s)
public DatabaseManagerTest()
{
Mock<IDatabaseManager> moqDB = new Mock<IDatabaseManager>();
//Setup send sms test
moqDB.Setup(md => md.SendSMS("0734233173", "Test message", "Ronny.Mahlangu")).Returns(true);
this._mockDatabaseManager = moqDB.Object;
}
and below is the actual test method
public void TestSendSms()
{
bool results = this._mockDatabaseManager.SendSMS("0734233173", "Test message", "Ronny.Mahlangu");
Assert.IsTrue(results);
}
My testing seem to pass, however I also want to unit test the action method itself, in this case I'm only testing whether sms sends successfully, how do I go about testing the action method itself, surely I need to mock the asmx service but I am blank
Also note that the SendSMS
method comes from a class named DatabaseManager
, which is where the asmx methods are being invoked, here is the peace of code from that class
public bool SendSMS(string cellNumber, string message, string logonName) {
if(string.IsNullOrWhiteSpace(cellNumber))
{
throw new ArgumentNullException("cell phone number is null");
}
if(string.IsNullOrWhiteSpace(message))
{
throw new ArgumentNullException("Sms message is null");
}
using (SMSService.SendSmsSoapClient sms = new SMSService.SendSmsSoapClient())
{
if (sms.SendDirect(cellNumber, message, ConfigurationManager.AppSettings["costCentre"], userLogonName, ConfigurationManager.AppSettings["source"]) == SMSService.Status.Successful)
{
SaveSmsDetails(cellNumber, message, userLogonName);
return true;
}
}
return false;
}
Upvotes: 3
Views: 687
Reputation: 247088
DatabaseManager
is a dependency of the controller that wraps the 3rd part call to the asmx service. You first test is actually testing the mock and is of not much use. To test the controller you need to provided the necessary dependencies for the action to flow to completion.
Here is a simple example.
Assuming the following interface based on original example in question..
public interface IDatabaseManager {
bool SendSMS(string cellNumber, string message, string logonName);
}
The following represents the controller under test in this example
public class SmsController : Controller {
private IDatabaseManager _dbManager;
public SmsController(IDatabaseManager databaseManager) {
this._dbManager = databaseManager;
}
public ActionResult CreateSms(SendSMSViewModel tblSend) {
if (ModelState.IsValid) {
if (_dbManager.SendSMS(tblSend.CellNumber, tblSend.Message, User.Identity.Name)) {
TempData["Success"] = "Message was successfully sent";
} else {
TempData["Error"] = "An error occured while sending the message";
}
}
return RedirectToAction("CreateSms");
}
}
Testing the action would require mocking the dependencies used in the action. The following show how one can do that.
[TestMethod]
public void TestCreateSms() {
//Arrange
var expectedCellNumber = "0734233173";
var expectedMessage = "Test message";
var expectedName = "Ronny.Mahlangu";
var expectedResult = true;
// - dependency mocked with desired behavior
var moqDB = new Mock<IDatabaseManager>();
moqDB
.Setup(md => md.SendSMS(expectedCellNumber, expectedMessage, expectedName))
.Returns(expectedResult)
.Verifiable();
// - Fake user for request in order to access User.Identity.Name
var principal = new ClaimsPrincipal(new GenericIdentity(expectedName));
var contextMock = new Mock<HttpContextBase>();
contextMock.Setup(_ => _.User).Returns(principal);
// - controller under test
var controller = new SmsController(moqDB.Object);
controller.ControllerContext = new ControllerContext(contextMock.Object, new RouteData(), controller);
// - view model sent to action
var tblSend = new SendSMSViewModel {
CellNumber = expectedCellNumber,
Message = expectedMessage
};
//Act
var result = controller.CreateSms(tblSend);
//Assert
moqDB.Verify(); //verify that the mock executed as expected
//you can also assert the results of calling the action to confirm expectations
Assert.IsTrue(controller.TempData.ContainsKey("Success"));
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
var redirectResult = result as RedirectToRouteResult;
Assert.AreEqual("CreateSms", redirectResult.RouteValues["action"]);
}
The above can be copied and modified to test other scenarios, like when SendSMS
fails, by simply making the mocked dependency return false
when called.
This should be enough to get you started.
Upvotes: 2