Reputation: 449
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
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
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