Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking two different results from the same method

I have two action methods, edit and delete(both post). These methods invoke methods from a DB interface. These interface method are implemented in a class called DBManager. In these methods a user gets edited and a boolean results is returned, same goes for the delete method, the returned result will either be true or false, depending on whether the deletion or edit was a success or not.

Now I want to mock the two results(true and false), here is my code where I setup the mocks:

//setup passed test
_moqDB.Setup(md => md.EditStaff(It.IsAny<StaffEditViewModel>())).Returns(true);

//setup failed test
_moqDB.Setup(md => md.EditStaff(It.IsAny<StaffEditViewModel>())).Returns(false);

//Setup Delete method test
_moqDB.Setup(x => x.DeleteStaffMember(It.IsAny<int>())).Returns(true);

//delete failed
_moqDB.Setup(x => x.DeleteStaffMember(It.IsAny<int>())).Returns(false);`

Here is my testing code

 [TestMethod]
    public void PostUpdatedUserTest()
    {
        var staffEdit = new StaffEditViewModel()
        {
            BranchID = "HQ",
            SiteID = "TestingSite",
            StaffEmail = "[email protected]",
            StaffID = 887,
            StaffNameF = "TestUser",
            StaffNameS = "TestSurname",
            StaffPassword = "****",
            StaffSecurity = UserRoles.Administrator
        };

        //Act
        var result = _userController.Edit(staffEdit);

        //Assert
        Assert.IsNotNull(result);
        Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
        var redirectResult = result as RedirectToRouteResult;
        Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
    }

    [TestMethod]
    public void PostUpdatedUserFailTest()
    {
        var staffEdit = new StaffEditViewModel()
        {
            BranchID = "HQ",
            SiteID = "TestSite",
            StaffEmail = "[email protected]",
            StaffID = 1,
            StaffNameF = "Test1",
            StaffNameS = "TestSurname",
            StaffPassword = "****",
            StaffSecurity = UserRoles.Administrator
        };

        //Act
        var result = _userController.Edit(staffEdit) as ViewResult;

        // Assert
        Assert.IsNotNull(result);
        Assert.IsTrue(string.IsNullOrEmpty(result.ViewName) || result.ViewName == "Error");
    }

The tests seems to pass only when I run them individually(run one while the other is commented out). My question is, is there a way of running this tests all at once and have them pass, remember I am trying to tests two different scenarios(true and false). They say assumption is the devil of all bugs, now I cannot assume just because false result seems to work fine then also the true result will be perfect

like image 467
Mronzer Avatar asked May 26 '17 06:05

Mronzer


People also ask

Can we mock same method twice?

We can stub a method with multiple return values for the consecutive calls.

How do you return different values each time a mocked method is called?

The alternative is to use the Moq feature Sequence which allows you to set multiple return values, that will be returned one at a time in order, each time the mocked method is called.

How do you tell a Mockito mock object to return something different the next time it is called?

For Anyone using spy() and the doReturn() instead of the when() method: what you need to return different object on different calls is this: doReturn(obj1). doReturn(obj2).


1 Answers

You can use a function in the Returns of the Setup to execute custom logic based on provided input when the mocked member is called.

_moqDB
    .Setup(_ => _.EditStaff(It.IsAny<StaffEditViewModel>()))
    .Returns((StaffEditViewModel arg) => {
        if(arg != null && arg.StaffID == 887) return true;
        else return false; //this will satisfy other Ids like 1
    });

_moqDB
    .Setup(_ => _.DeleteStaffMember(It.IsAny<int>()))
    .Returns((int staffId) => {
        if(staffId == 887) return true;
        else return false; //this will satisfy other Ids like 1
    });

You can implement what ever logic within the Func to satisfy multiple scenarios for your tests.

Also as mentioned in the comments try to arrange once per test so that setups do not override each other when run together as the last setup on a member will override any previous ones that match. It simplifies that testing process as each unit test should be run in isolation and should not be affected by other tests in the list.

like image 56
Nkosi Avatar answered Oct 25 '22 01:10

Nkosi