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; 
}

      

+3


source to share


1 answer


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.

+2


source







All Articles