How to use moq to unit test an application that uses an asmx service in .NET.
I have a web application that sends sms by using ASMX service (which is up and running fine now), however now I need to unit test, this application is using 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 the view model as a parameter, this vmodel has 2 properties (cell number, message), and there is also a user who is sending sms. Now in my unit test or integration (apologies, which I will also confuse in two) I have the following code, this first part, I am just trying to make fun of 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 seems to pass, however I also want to unit test the action method itself, in this case I only check if the sms message is successful, how do I get the action method itself tested, of course I need to mock the asmx service, but I am empty
Also note that the method SendSMS
comes from a named class DatabaseManager
in which the asmx method is called, here is the code world 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;
}
source to share
DatabaseManager
is the controller dependency that completes the call to the third part to the asmx service. Your first test is actually mock testing and is not very helpful. To test the controller, you need to provide the required dependencies to complete the action.
Here's a simple example.
Assuming the following interface based on the original example in question.
public interface IDatabaseManager {
bool SendSMS(string cellNumber, string message, string logonName);
}
Below is the test controller 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 an action will require mocking the dependencies used in the action. Here's how you can do this.
[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, such as when it SendSMS
fails, by simply making the dispatched dependency return false
when called.
This should be enough to get you started.
source to share