Mocking two different results from the same method - c#

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 = "Zandile.Mashele#avisbudget.co.za",
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 = "Zandile.Mashele#avisbudget.co.za",
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

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.

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.

Related

FakeItEasy not finding call although its there

I experience some strange problems with FakeItEasy.
Imagine following unit test method:
[TestMethod]
public void DeletePerson_WhenCalled_ThenPersonIsDeleted()
{
const int personId = 24;
var commonParam = new CommonParam();
this.testee.DeletePerson(commonParam, personId );
A.CallTo(() => this.personRepository.DeletePersons(commonParam, new[] {personId }, false)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => this.personRepository.SaveChanges()).MustHaveHappened(Repeated.Exactly.Once);
}
The testee.DeletePerson-method looks like this:
public ResultatModel DeletePerson(CommonParam commonParam, int personId )
{
this.personRepository.DeletePersons(commonParam, new[] { personId });
this.personRepository.SaveChanges();
}
And the personRepository.DeletePersons (but this one is faked by fakeiteasy...):
public void DeletePersons(CommonParam commonParam, IEnumerable<int> ids, bool hardRemove = false)
{
var persons = Entities.per_person.Where(e => ids.Contains(e.personId)
&& (e.accountId == null || e.accountId == commonParam.AccountId)).ToList();
if (hardRemove)
{
Entities.per_person.RemoveRange(persons);
}
else
{
persons.ForEach(person =>
{
person.geloescht = true;
person.mutationsBenutzer = commonParam.DbIdent;
person.mutationsDatum = DateTime.Now;
});
}
}
This is the reason why the test fails
Test method DataService.Test.PersonServiceTest.DeletePerson_WhenCalled_ThenPersonIsDeleted threw exception:
FakeItEasy.ExpectationException:
Assertion failed for the following call:
RepositoryContract.IPersonRepository.DeletePersons(commonParam: Commons.CommonParam, ids: System.Int32[], hardRemove: False)
Expected to find it exactly once but found it #0 times among the calls:
1: RepositoryContract.IPersonRepository.RequestInfo = Faked Commons.Session.RequestInfo
2: RepositoryContract.IPersonRepository.DeletePersons(
commonParam: Commons.CommonParam,
ids: System.Int32[],
hardRemove: False)
3: RepositoryContract.IPersonRepository.SaveChanges()
Why does the test fail?
Is the new[] { ... } a problem?
Thanks in advance
Is the new[] { ... } a problem?
Yes,
MustHaveHappened(Repeated.Exactly.Once) will "pass" only when mocked method will be called with exact same parameters which you provide in the mock configuration.
A.CallTo(() => this.personRepository.DeletePersons(commonParam, new[] {personId }, false))
.MustHaveHappened(Repeated.Exactly.Once);
For commonParam it works, because you passed same instance to the method under the test.
For new[] {personId } it doesn't work because array given in mock configuration and instance given in the method under the test are different instances of int[].
You can use custom argument matching
A.CallTo(() => this.personRepository.DeletePersons(
commonParam,
A<IEnumerable<int>>.That.Matches(ids => ids.Single() == personId),
false))
.MustHaveHappened(Repeated.Exactly.Once);
Or use more convenience and readable matching for your particular case as Thomas suggested. More convenience matchers
Fabio is correct, but you can make it a bit simpler:
A.CallTo(() => this.personRepository.DeletePersons(
commonParam,
A<IEnumerable<int>>.That.IsSameSequenceAs(personId),
false))
.MustHaveHappened(Repeated.Exactly.Once);
Is the new[] { ... } a problem?
Yes you are right. The new[] creates an array with the type you use between the {...} (It's assumed by the compiler). However your method declaration uses a IEnumerable<int> ids. So basically your test call is calling the wrong/unexisting method, due to signature mismatch.

Moq Expression with Constraint ... It.Is<Expression<Func<T, bool>>>

Ok, I am having a hard time trying to figure out how to setup a moq for a method that takes in an expression. There are a lot of examples out there of how to to It.IsAny<>... that is not what I am after. I am after doing with a constraint, so It.Is<>. I have set it up but it never returns the value I have asked it to return.
// Expression being setup
Expression<Func<UserBinding, bool>> testExpression = binding =>
binding.User.Username == "Testing Framework";
// Setup of what expression to look for.
this.bindingManager.Setup(
c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>
(criteria => criteria == testExpression)))
.Returns(new List<UserBinding>() { testBinding }.AsQueryable());
// Line of code call from within the class being tested. So this is being mocked and should return the defined object when the same lambda is passed in.
this.bindingManager.GetUserBinding(b => b.User.Username == username)
.SingleOrDefault();
// class under test. So for the test this is being called.
// so this is the method being called and inside this method is where the binding manager is being mocked and called.
var response = this.controller.SendMessage(message, true).Result;
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
// inside the controller.SendMessage method this method is called with the lambda expression. I have verified the usernames match but when the setup is It.Is this returns null instead of the object setup in the "setup" call.
this.bindingManager.GetUserBinding(b => b.User.Username == username)
.SingleOrDefault();
If I change the setup to It.IsAny... It works and returns the expected object setup in the "returns" method.
I have found a few examples of how to do this on the web one is doing it this way the other is using compile but I can't get that to work either. How do you get this to work for a specific expression?
Update with working solution based on answer
#carlos-alejo got me going in the right direction or at least kicked me back to the Compile action. I was thinking about it wrong. I have the solution working now based on using compile. The key thing to understand about compile is you are giving it an object by which to evaluate/generate the expression for.
So in my case if some one is giving me an expression like this:
binding => binding.User.Username == "Testing Framework";
I need to have a UserBinding like this:
var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework" } };
I can then create my "setup" call like this:
this.bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>(y => y.Compile()(testBinding))))
.Returns(new List<UserBinding>() { testBinding }.AsQueryable());
This works and in my case returns me back the test binding object as I have setup. If you change the testBinding to be (notice I changed the user name):
var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework2" } };
It will not work because the code inside my system under test generates an expression looking for "Test Framework"
Maybe it was just me not connecting the dots on this but hopefully it helps others.
It seems that the real problem here is how to compare two lambda expressions, as you try to do in the It.Is<Expression<Func<UserBinding, bool>>> (criteria => criteria == testExpression) clause. Using #neleus's answer to this question, I could come up with this test that actually passes:
readonly Mock<IBindingManager> bindingManager = new Mock<IBindingManager>();
[Test]
public void TestMethod()
{
Expression<Func<string, bool>> testExpression = binding => (binding == "Testing Framework");
bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
criteria => LambdaCompare.Eq(criteria, testExpression)))).Returns(new List<string>());
var oc = new OtherClass(bindingManager.Object);
var actual = oc.Test(b => b == "Testing Framework");
Assert.That(actual, Is.Not.Null);
bindingManager.Verify(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
criteria => LambdaCompare.Eq(criteria, testExpression))), Times.Once());
}
Please note the use of the LambdaCompare.Eq static method to compare that the expressions are the same. If I compare the expressions just with == or even Equals, the test fails.
When I was looking for the way to to mock Where() and filter some data,
in code under tests looks like:
Repository<Customer>().Where(x=>x.IsActive).ToList()
I could design such example based on answers form others:
var inputTestDataAsNonFilteredCustomers = new List<Customer> {cust1, cust2};
var customersRepoMock = new Mock<IBaseRepository<Customer>>();
IQueryable<Customer> filteredResult = null;
customersRepoMock.Setup(x => x.Where(It.IsAny<Expression<Func<Customer, bool>>>()))
.Callback((Expression<Func<Customer, bool>>[] expressions) =>
{
if (expressions == null || expressions.Any() == false)
{
return;
}
Func<Customer, bool> wereLambdaExpression = expressions.First().Compile(); // x=>x.isActive is here
filteredResult = inputTestDataAsNonFilteredCustomers.Where(wereLambdaExpression).ToList().AsQueryable();// x=>x.isActive was applied
})
.Returns(() => filteredResult.AsQueryable());
Maybe it will be helpful for feather developers.

Moq setup does not return value while told

I have this in my test scenario:
var dbConnection = new Mock<IDbConnection>();
dbConnection.Setup(x => x.SearchFor<User>("users", y => y.Password =="12345"
&& y.Username == "tester")).Returns(new List<User>{
new User{
Username = "tester",
Password = "12345"
}}.AsQueryable());
var users = new Users.Users(dbConnection.Object);
var user = users.Get("tester", "12345");
When looking at the Get method:
public User Get(string username, string password){
var total = _dbConnection.SearchFor<User>("users", y =>
y.Password == password &&
y.Username == username).Single();
return total;
}
It should work according by most of the samples I found on the internet, but it always gives me:
System.InvalidOperationException: Sequence contains no elements
When I change my Get method to this:
public User Get(string username, string password){
var total = _dbConnection.SearchFor<User>("users", y =>
y.Password == "12345" &&
y.Username == "tester").Single();
return total;
}
It magicaly works, but the get method is in a business layer and like we all know... to set a username and password hardcoded is never good.
The question is: How can I get the setup for moq work properly? What am I doing wrong?
so you're setting up, expecting the paramters "users" and y => y.Password == "12345" && y.UserName == "tester". However, your second parameter is a lambda, which are hard to compare (if not impossible?). So, when Moq is checking to see if you've called that, it's ultimately trying to compare lambdas, which will probably fail.
For example the following code shows two seemingly identical functions, but they are not considered to be equal:
Func<bool> a = () => true;
Func<bool> b = () => true;
(a == b).Dump(); //False
a.Equals(b).Dump(); //False
Therefore Moq doesn't know to use the return value that you setup.
You may need to implement a mock repository that will actually run the lambda instead of trying to find the same one that you provided.
Something like this:
class TestRepo
{
public void Add<T>(T myType)
{
//add to an in-memory "database"
}
public IEnumerable<T> Get<T>(Expression<Func<T, bool>> filter)
{
return inMemoryDataBase.Where(filter);
}
}
Which would make your Get method look something like this:
public User Get(string username, string password){
var total = RealRepo.Get<User>(y =>
y.Password == "12345" &&
y.Username == "tester").Single();
return total;
}
And your test:
var repo = new TestRepo();
repo.Add(new User { Username = "tester", Password = "12345" });
var users = new Users.Users(dbConnection.Object);
var user = users.Get("tester", "12345");
Here is a somewhat related question where a user was trying to find a way to uniquely identify a lambda so that they could be "compared" in the way you're hoping for. I don't know that any perfect solutions were found there. Link

Different return values the first and second time with Moq

I have a test like this:
[TestCase("~/page/myaction")]
public void Page_With_Custom_Action(string path) {
// Arrange
var pathData = new Mock<IPathData>();
var pageModel = new Mock<IPageModel>();
var repository = new Mock<IPageRepository>();
var mapper = new Mock<IControllerMapper>();
var container = new Mock<IContainer>();
container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageModel.Object);
pathData.Setup(x => x.Action).Returns("myaction");
pathData.Setup(x => x.Controller).Returns("page");
var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);
// Act
var data = resolver.ResolvePath(path);
// Assert
Assert.NotNull(data);
Assert.AreEqual("myaction", data.Action);
Assert.AreEqual("page", data.Controller);
}
GetPageByUrl runs twice in my DashboardPathResolver, how can I tell Moq to return null the first time and pageModel.Object the second?
With the latest version of Moq(4.2.1312.1622), you can setup a sequence of events using SetupSequence. Here's an example:
_mockClient.SetupSequence(m => m.Connect(It.IsAny<String>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new SocketException())
.Throws(new SocketException())
.Returns(true)
.Throws(new SocketException())
.Returns(true);
Calling connect will only be successful on the third and fifth attempt otherwise an exception will be thrown.
So for your example it would just be something like:
repository.SetupSequence(x => x.GetPageByUrl<IPageModel>(virtualUrl))
.Returns(null)
.Returns(pageModel.Object);
The existing answers are great, but I thought I'd throw in my alternative which just uses System.Collections.Generic.Queue and doesn't require any special knowledge of the mocking framework - since I didn't have any when I wrote it! :)
var pageModel = new Mock<IPageModel>();
IPageModel pageModelNull = null;
var pageModels = new Queue<IPageModel>();
pageModels.Enqueue(pageModelNull);
pageModels.Enqueue(pageModel.Object);
Then...
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(pageModels.Dequeue);
Now you can use SetupSequence. See this post.
var mock = new Mock<IFoo>();
mock.SetupSequence(f => f.GetCount())
.Returns(3) // will be returned on 1st invocation
.Returns(2) // will be returned on 2nd invocation
.Returns(1) // will be returned on 3rd invocation
.Returns(0) // will be returned on 4th invocation
.Throws(new InvalidOperationException()); // will be thrown on 5th invocation
You can use a callback when setting up your mock object. Take a look at the example from the Moq Wiki (https://github.com/Moq/moq4/wiki/Quickstart).
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());
Your setup might look like this:
var pageObject = pageModel.Object;
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageObject).Callback(() =>
{
// assign new value for second call
pageObject = new PageModel();
});
Adding a callback did not work for me, I used this approach instead http://haacked.com/archive/2009/09/29/moq-sequences.aspx and I ended up with a test like this:
[TestCase("~/page/myaction")]
[TestCase("~/page/myaction/")]
public void Page_With_Custom_Action(string virtualUrl) {
// Arrange
var pathData = new Mock<IPathData>();
var pageModel = new Mock<IPageModel>();
var repository = new Mock<IPageRepository>();
var mapper = new Mock<IControllerMapper>();
var container = new Mock<IContainer>();
container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);
repository.Setup(x => x.GetPageByUrl<IPageModel>(virtualUrl)).ReturnsInOrder(null, pageModel.Object);
pathData.Setup(x => x.Action).Returns("myaction");
pathData.Setup(x => x.Controller).Returns("page");
var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);
// Act
var data = resolver.ResolvePath(virtualUrl);
// Assert
Assert.NotNull(data);
Assert.AreEqual("myaction", data.Action);
Assert.AreEqual("page", data.Controller);
}
The accepted answer, as well as the SetupSequence answer, handles returning constants.
Returns() has some useful overloads where you can return a value based on the parameters that were sent to the mocked method. Based on the solution given in the accepted answer, here is another extension method for those overloads.
public static class MoqExtensions
{
public static IReturnsResult<TMock> ReturnsInOrder<TMock, TResult, T1>(this ISetup<TMock, TResult> setup, params Func<T1, TResult>[] valueFunctions)
where TMock : class
{
var queue = new Queue<Func<T1, TResult>>(valueFunctions);
return setup.Returns<T1>(arg => queue.Dequeue()(arg));
}
}
Unfortunately, using the method requires you to specify some template parameters, but the result is still quite readable.
repository
.Setup(x => x.GetPageByUrl<IPageModel>(path))
.ReturnsInOrder(new Func<string, IPageModel>[]
{
p => null, // Here, the return value can depend on the path parameter
p => pageModel.Object,
});
Create overloads for the extension method with multiple parameters (T2, T3, etc) if needed.
Reached here for the same kind of problem with slightly different requirement.
I need to get different return values from mock based in different input values and found solution which IMO more readable as it uses Moq's declarative syntax (linq to Mocks).
public interface IDataAccess
{
DbValue GetFromDb(int accountId);
}
var dataAccessMock = Mock.Of<IDataAccess>
(da => da.GetFromDb(It.Is<int>(acctId => acctId == 0)) == new Account { AccountStatus = AccountStatus.None }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 1)) == new DbValue { AccountStatus = AccountStatus.InActive }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 2)) == new DbValue { AccountStatus = AccountStatus.Deleted });
var result1 = dataAccessMock.GetFromDb(0); // returns DbValue of "None" AccountStatus
var result2 = dataAccessMock.GetFromDb(1); // returns DbValue of "InActive" AccountStatus
var result3 = dataAccessMock.GetFromDb(2); // returns DbValue of "Deleted" AccountStatus
We can simply declare one variable with int as a datatype. initialize it to zero, and then increase it's value as follows:
int firstTime = 0;
repository.Setup(_ => _.GetPageByUrl<IPageModel>(path)).Returns(() =>
{
if (firstTime == 0)
{
firstTime = 1;
return null;
}
else if(firstTime == 1)
{
firstTime = 2;
return pageModel.Object;
}
else
{
return null;
}
});
In some cases one needs to have the called function return different types of data based on conditions you cannot impose via the function itself. If the function accepts parameters then those can be used as conditionals to get different data.
In my case, I had a webapi call which I need to mock; earlier it was working out fine based on the input parameter, however one fine day, those parameters were converted to request headers. So since I couldn't provide a callback (no function parameters) so came up with another approach as follows
[Earlier one, when API had parameters]
this.mockedMasterAPICalls.Setup(m => m.GetCountries(It.Is<int>(ou => ou == 2), It.Is<int>(lan => lan == 1))).Returns(Task.FromResult(countryResponse));
[New one, when API had headers... The headers were getting injected into another dictionary of the API caller]
this.mockedMasterAPICalls.Setup(m => m.RequestHeaders).Returns(new Dictionary<string, string>());
this.mockedMasterAPICalls.Setup(m => m.GetCountries()).Returns(() =>
{
if (this.mockedMasterAPICalls.Object.RequestHeaders[GlobalConstants.HeaderOUInstance] == "2")
return Task.FromResult(countryResponse);
else return Task.FromResult(new GetCountryResponse() { Countries = null });
});
Note the use of the mocked object itself to make any decisions required

Verifying a specific parameter with Moq

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
var messageServiceClientMock = new Mock<IMessageServiceClient>();
var queueableMessage = CreateSingleQueueableMessage();
var message = queueableMessage[0];
var xml = QueueableMessageAsXml(queueableMessage);
messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable();
//messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object);
var loggerStub = new Mock<ILogger>();
var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});
//messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once());
messageServiceClientMock.Verify();
}
I'm starting using Moq and struggling a bit.
I'm trying to verify that messageServiceClient is receiving the right parameter, which is an XmlElement, but I can't find any way to make it work. It works only when I don't check a particular value.
Any ideas?
Partial answer:
I've found a way to test that the xml sent to the proxy is correct, but I still don't think it's the right way to do it.
public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
var messageServiceClientMock = new Mock<IMessageServiceClient>();
messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object);
var loggerStub = new Mock<ILogger>();
var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
var message = CreateMessage();
client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});
messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once());
}
By the way, how could I extract the expression from the Verify call?
If the verification logic is non-trivial, it will be messy to write a large lambda method (as your example shows). You could put all the test statements in a separate method, but I don't like to do this because it disrupts the flow of reading the test code.
Another option is to use a callback on the Setup call to store the value that was passed into the mocked method, and then write standard Assert methods to validate it. For example:
// Arrange
MyObject saveObject;
mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()))
.Callback<int, MyObject>((i, obj) => saveObject = obj)
.Returns("xyzzy");
// Act
// ...
// Assert
// Verify Method was called once only
mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once());
// Assert about saveObject
Assert.That(saveObject.TheProperty, Is.EqualTo(2));
I've been verifying calls in the same manner - I believe it is the right way to do it.
mockSomething.Verify(ms => ms.Method(
It.IsAny<int>(),
It.Is<MyObject>(mo => mo.Id == 5 && mo.description == "test")
), Times.Once());
If your lambda expression becomes unwieldy, you could create a function that takes MyObject as input and outputs true/false...
mockSomething.Verify(ms => ms.Method(
It.IsAny<int>(),
It.Is<MyObject>(mo => MyObjectFunc(mo))
), Times.Once());
private bool MyObjectFunc(MyObject myObject)
{
return myObject.Id == 5 && myObject.description == "test";
}
Also, be aware of a bug with Mock where the error message states that the method was called multiple times when it wasn't called at all. They might have fixed it by now - but if you see that message you might consider verifying that the method was actually called.
EDIT: Here is an example of calling verify multiple times for those scenarios where you want to verify that you call a function for each object in a list (for example).
foreach (var item in myList)
mockRepository.Verify(mr => mr.Update(
It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated),
Times.Once());
Same approach for setup...
foreach (var item in myList) {
var stuff = ... // some result specific to the item
this.mockRepository
.Setup(mr => mr.GetStuff(item.itemId))
.Returns(stuff);
}
So each time GetStuff is called for that itemId, it will return stuff specific to that item. Alternatively, you could use a function that takes itemId as input and returns stuff.
this.mockRepository
.Setup(mr => mr.GetStuff(It.IsAny<int>()))
.Returns((int id) => SomeFunctionThatReturnsStuff(id));
One other method I saw on a blog some time back (Phil Haack perhaps?) had setup returning from some kind of dequeue object - each time the function was called it would pull an item from a queue.
A simpler way would be to do:
ObjectA.Verify(
a => a.Execute(
It.Is<Params>(p => p.Id == 7)
)
);
I believe that the problem in the fact that Moq will check for equality. And, since XmlElement does not override Equals, it's implementation will check for reference equality.
Can't you use a custom object, so you can override equals?
Had one of these as well, but the parameter of the action was an interface with no public properties. Ended up using It.Is() with a seperate method and within this method had to do some mocking of the interface
public interface IQuery
{
IQuery SetSomeFields(string info);
}
void DoSomeQuerying(Action<IQuery> queryThing);
mockedObject.Setup(m => m.DoSomeQuerying(It.Is<Action<IQuery>>(q => MyCheckingMethod(q)));
private bool MyCheckingMethod(Action<IQuery> queryAction)
{
var mockQuery = new Mock<IQuery>();
mockQuery.Setup(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition())
queryAction.Invoke(mockQuery.Object);
mockQuery.Verify(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition(), Times.Once)
return true
}

Categories

Resources