Mronzer
Mronzer

Reputation: 449

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

Upvotes: 6

Views: 12488

Answers (2)

Nkosi
Nkosi

Reputation: 247581

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.

Upvotes: 7

kayess
kayess

Reputation: 3394

You have given no condition when Moq should return true or false. Just change the setup of the edit use case as:

_moqDB.Setup(md => md.EditStaff(It.Is<StaffEditViewModel>(x => x.StaffID == 887))).Returns(true);

_moqDB.Setup(md => md.EditStaff(It.Is<StaffEditViewModel>(x => x.StaffID == 1))).Returns(false);

The noticable change here is the use of It.Is() instead your It.IsAny(). From the documentation:

It.IsAny():

Matches any value of the given TValue type

It.Is():

Matches any value that satisfies the given predicate.

Upvotes: 4

Related Questions