Moq lambda expression behaving unexpectedly - c#

I have a unit test using MOQ that's behaving unexpectedly. I'm expecting the IsAuthorizedAsync method to always return true, but it's returning false. Here's a simplified version of the code that's adding the IsAuthorizedAsync method to my Mock Object.
public static IAuthenticationInterface GetAuthentication()
{
var mock = new Mock<IAuthenticationInterface>();
mock.Setup(e => e.IsAuthorizedAsync(It.IsIn<string>(), It.IsAny<MyEvent>())).Returns(System.Threading.Tasks.Task.FromResult(true)).Verifiable();
// return the mock object
return mock.Object;
}
Here's code similar to the code that's using it:
bool isAuthorized = this.mockObject != null && await this.mockObject.IsAuthorizedAsync("abc123", myEvent).ConfigureAwait(false);
Like I said, it's returning false when it looks to me like it should always return true. Is there any way for me to step into the lambda expression code? Alternatively, is there any way for me to view what the actual lambda expression that's being used when I call this.mockObject.IsAuthorizedAsync? I suspect it's not what I think it is.
-Eric

As per #tzachs' comment, note that the It.IsIn matcher takes a list of matching values (strings in your instance). It.IsIn() with an empty params or IEnumerable will never match anything, as it is implemented with .Contains:
public static TValue IsIn<TValue>(IEnumerable<TValue> items)
{
return Match.Create<TValue>((Predicate<TValue>)
(value => Enumerable.Contains<TValue>(items, value)),
(Expression<Func<TValue>>) (() => It.IsIn<TValue>(items)));
}
hence the failure to return the desired result. You'll want to either change this e.g.
It.IsAny<string>() // ... Any string at all
It.Is<string>(s => s == "Foo") // ... Match via a Predicate
It.IsIn<string>("Foo", "Bar", "Baz") // ... Match via a List
Also, note that when working with Async methods, that Moq (and Test Frameworks like NUnit and XUnit) have support for Async semantics. So instead of 'hacking' a Task.FromResult, what you can do instead is:
[Test]
public async void MyTest() // ... The UT can be made async
{
var mock = new Mock<IAuthenticationInterface>();
mock.Setup(e => e.IsAuthorizedAsync(It.IsIn<string>("Foo"), It.IsAny<MyEvent>()))
.ReturnsAsync(true) // ... Async
.Verifiable();
// async calls can be awaited
Assert.True(await mock.Object.IsAuthorizedAsync("Foo", null));
}
(and yes, I know I'm just testing the Mock here :)

Related

Moq - passing arguments from setup() to returns()

I am not sure how to pass arguments from Setup() to Returns() in Moq.
Here is an example:
public static IInterfaceHandler GetInterfaceHandlerMoq()
{
// Defining the moq
var moq = new Mock<IInterfaceHandler>();
// Trying to set up a moq using another moq
moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
.Returns((Guid guid, string value) => GetProgrammerMoq(guid, value));
// Return mocked object
return moq.Object;
}
Note that GetProgrammerMoq() is a library that will return another Moq. Here is the code:
public static IProgrammer GetProgrammerMoq(Guid guid, string instName)
{
// Create Moq
var moq = new Mock<IProgrammer>();
// Set up the returnables
moq.Setup(o => o.InstanceName).Returns(programmer + "_" + instName);
moq.Setup(o => o.Guid).Returns(guid);
// Return mocked object
return moq.Object;
}
See here that GetProgrammerMoq() needs its arguments to be set up based on what is passed to CreateCommunicationInterface().
My test then tries to get and use the Moq, but "p" is returned as null (because, I guess, my arguments are not passed properly to Returns()).
Here is a draft of what the test is to look like:
[Fact]
public void DoSomething()
{
IInterfaceHandler test = ProgrammerMoqs.GetInterfaceHandlerMoq();
Guid? g = new Guid();
IProgrammer p = test.CreateCommunicationInterface(g, "test-boff");
...
}
Try this:
var moq = new Mock<IInterfaceHandler>(MockBehavior.Strict);
MockBehavior.Strict: if you get NULLs from Mock, then always try MockBehavior.Strict. When some setup is not prepared, Moq by default returns NULL. But with MockBehavior.Strict, it will throw an exception. Every single attempt to call anything from the mock object, if it lacks proper setup, will throw.
If you get an exception when trying MockBehavior.Strict, then it means that the:
.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
failed to catch the invocatio, so the mock returned NULL by default.
Why did it fail to catch the invocation? There are several options:
CreateCommunicationInterface may be overloaded and your setup matched another overload that you did not expect
filters (It.IsAny..) didn't match the actual arguments
(..)
Klaus Gütter noted in the comments about the difference of Guid and Guid?. In fact, the filter you are using is It.IsAny() while in the test you pass:
Guid? g = new Guid();
g is not an object of type Guid, it's Nullable<Guid>, hence the filter looking for any-Guid did not match. The code compiled, because the result of the expression It.IsAny<Guid>() fits Guid? wanted by the method, but still the types don't match.
If you try It.IsAny<Guid?>() it will probably match fine and return what you wanted.
moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid?>(), It.IsAny<string>()))
.Returns((Guid? guid, string value) => GetProgrammerMoq(guid, value));

How to find out if method was called in a bool value in Rhino mocks?

I'm trying to write a parameterized unit test using NUnit and Rhino Mocks that can return true or false depending on whether a certain mocked method was called. AssertWasCalled is not right because it makes the test fail right away. I only want a bool value.
[Test]
[TestCase(1,2, Result=false)]
[TestCase(1,1, Result=true)]
public bool SomeTest(int a, int b)
{
...
someObject.CheckValues(a, b); // logs something if values are different.
return mockLogger.WasCalled(x => x.Log(null));
}
WasCalled ofc does't exist.
Stub the Log method on mockLogger to set a bool when it's called, and return that:
bool logMethodWasCalled = false;
mockLogger
.Stub(x => x.Log(Arg<string>.Is.Equal(null))
.Do(new Action<string>(_ => logMethodWasCalled = true));
// Run test...
return logMethodWasCalled;
It's better to use expectation:
mockLogger.Expect(x => x.Log(Arg<string>.Is.Anything));
mockLogger.VerifyAllExpectations();
If you want to check if parameter is null use:
mockLogger.Expect(x => x.Log(Arg<string>.Is.Null));
Another way is to use:
triggerManagerMock.AssertWasCalled(x => x.Log(Arg<string>.Is.Anything));
It that case you can use Stub method to model behavior and AssertWasCalled to check the call.

Verifying a call parameter via a callback in NSubstitute

I have a failing test in NSubstitute because a parameter passed in to a substituted call does not match. Here is the relevant code that is being tested:
// Arrange
PermissionsProviderSub = Substitute.For<IPermissionsProvider>();
MenuDataProviderSub = Substitute.For<IMenuDataProvider>();
PermissionsProviderSub.GetPermissions(UserId).Returns(ExpectedUserPermissions);
MenuDataProviderSub.GetMenuData(ExpectedUserPermissions.AuthorisedPageIds).Returns(Arg.Any<IList<BusinessFocusArea>>());
var sut = new MenuViewModelFactory(MenuDataProviderSub, PermissionsProviderSub);
// Act
var result = sut.Create();
// Assert
MenuDataProviderSub.Received().GetMenuData(ExpectedUserPermissions.AuthorisedPageIds);
The problem occurs in the ExpectedUserPermissions.AuthorisedPageIds property, which looks like this:
public IEnumerable<string> AuthorisedPageIds
{
get
{
return ApplicationPagePermissions != null ?
ApplicationPagePermissions.Select(permissionSet => permissionSet.PageId) :
Enumerable.Empty<string>();
}
}
As you can see, there is a LINQ Select, which is extracting the PageId property from within the ApplicationPagePermissions collection and returning it as an IEnumerable<string>. Because the projection within that property creates a new object, the substitution does not match, as it sees the 2 objects as being different.
Can I create a callback on the parameter passed in to GetMenuData so that I can examine the value of it?
The documentation on NSubstitute callbacks only talks about examining the return value from a call, rather than a parameter passed into the call.
Typical. As soon as I post to SO, the answer presents itself. Rather than expecting a specific object when creating the substitute call, I expect any instance of type IEnumerable<string> and create a callback when checking the Received() call that actually verifies the values. The substitute call becomes this:
MenuDataProviderSub.GetMenuData(Arg.Any<IEnumerable<string>>()).Returns(Arg.Any<IList<BusinessFocusArea>>());
The Received() check becomes this:
MenuDataProviderSub.Received().GetMenuData(Arg.Is<IEnumerable<string>>(a => VerifyPageIds(ExpectedUserPermissions.AuthorisedPageIds, a)));
private static bool VerifyPageIds(IEnumerable<string> expected, IEnumerable<string> actual)
{
var expectedIds = expected.ToList();
var actualIds = actual.ToList();
return expectedIds.Count == actualIds.Count && expectedIds.All(actualIds.Contains);
}

SetupSequence in Moq

I want a mock that returns 0 the first time, then returns 1 anytime the method is called thereafter. The problem is that if the method is called 4 times, I have to write:
mock.SetupSequence(x => x.GetNumber())
.Returns(0)
.Returns(1)
.Returns(1)
.Returns(1);
Otherwise, the method returns null.
Is there any way to write that, after the initial call, the method returns 1?
The cleanest way is to create a Queue and pass .Dequeue method to Returns
.Returns(new Queue<int>(new[] { 0, 1, 1, 1 }).Dequeue);
That's not particulary fancy, but I think it would work:
var firstTime = true;
mock.Setup(x => x.GetNumber())
.Returns(()=>
{
if(!firstTime)
return 1;
firstTime = false;
return 0;
});
Bit late to the party, but if you want to still use Moq's API, you could call the Setup function in the action on the final Returns call:
var mock = new Mock<IFoo>();
mock.SetupSequence(m => m.GetNumber())
.Returns(4)
.Returns(() =>
{
// Subsequent Setup or SetupSequence calls "overwrite" their predecessors:
// you'll get 1 from here on out.
mock.Setup(m => m.GetNumber()).Returns(1);
return 1;
});
var o = mock.Object;
Assert.Equal(4, o.GetNumber());
Assert.Equal(1, o.GetNumber());
Assert.Equal(1, o.GetNumber());
// etc...
I wanted to demonstrate using StepSequence, but for the OP's specific case, you could simplify and have everything in a Setup method:
mock.Setup(m => m.GetNumber())
.Returns(() =>
{
mock.Setup(m => m.GetNumber()).Returns(1);
return 4;
});
Tested everything here with xunit#2.4.1 and Moq#4.14.1 - passes ✔
You can use a temporary variable to keep track of how many times the method was called.
Example:
public interface ITest
{ Int32 GetNumber(); }
static class Program
{
static void Main()
{
var a = new Mock<ITest>();
var f = 0;
a.Setup(x => x.GetNumber()).Returns(() => f++ == 0 ? 0 : 1);
Debug.Assert(a.Object.GetNumber() == 0);
for (var i = 0; i<100; i++)
Debug.Assert(a.Object.GetNumber() == 1);
}
}
Just setup an extension method like:
public static T Denqueue<T>(this Queue<T> queue)
{
var item = queue.Dequeue();
queue.Enqueue(item);
return item;
}
And then setup the return like:
var queue = new Queue<int>(new []{0, 1, 1, 1});
mock.Setup(m => m.GetNumber).Returns(queue.Denqueue);
Normally, I wouldn't bother submitting a new answer to such an old question, but in recent years ReturnsAsync has become very common, which makes potential answers more complicated.
As other have stated, you can essentially just create a queue of results and in your Returns call pass the queue.Dequeue delegate.
Eg.
var queue = new Queue<int>(new []{0,1,2,3});
mock.SetupSequence(m => m.Bar()).Returns(queue.Dequeue);
However, if you are setting up for an async method, we should normally call ReturnsAsync. queue.Dequeue when passed into ReturnsAsync and will result in the first call to the method being setup working correctly, but subsequent calls to throw a Null Reference Exception. You could as some of the other examples have done create your own extension method which returns a task, however this approach does not work with SetupSequence, and must use Returns instead of ReturnsAsync. Also, having to create an extension method to handle returning the results kind of defeats the purpose of using Moq in the first place. And in any case, any method which has a return type of Task where you have passed a delegate to Returns or ReturnsAsync will always fail on the second call when setting up via SetupSequence.
There are however two amusing alternatives to this approach that require only minimal additional code. The first option is to recognize that the Mock object's Setup and SetupAsync follow the Fluent Api design patterns. What this means, is that technically, Setup, SetupAsync, Returns and ReturnsAsync actually all return a "Builder" object. What I'm referring to as a Builder type object are fluent api style objects like QueryBuilder, StringBuilder, ModelBuilder and IServiceCollection/IServiceProvider. The practical upshot of this is that we can easily do this:
var queue = new List<int>(){0,1,2,3};
var setup = mock.SetupSequence(m => m.BarAsync());
foreach(var item in queue)
{
setup.ReturnsAsync(item);
}
This approach allows us to use both SetupSequence and ReturnsAsync, which in my opinion follows the more intuitive design pattern.
The second approach is to realize that Returns is capable of accepting a delegate which returns a Task, and that Setup will always return the same thing. This means that if we were to either create an an extension method for Queue like this:
public static class EMs
{
public static async Task<T> DequeueAsync<T>(this Queue<T> queue)
{
return queue.Dequeue();
}
}
Then we could simply write:
var queue = new Queue<int>(new []{0,1,2,3});
mock.Setup(m => m.BarAsync()).Returns(queue.DequeueAsync);
Or would could make use of the AsyncQueue class from Microsoft.VisualStudio.Threading, which would allow us to do this:
var queue = new AsyncQueue<int>(new []{0,1,2,3});
mock.Setup(m => m.BarAsync()).Returns(queue.DequeueAsync);
The main problem that causes all of this, as that when the end of a setup sequence has been reached, the method is treated as not being setup. To avoid this, you are expected to also call a standard Setup if results should be returned after the end of the sequence has been reached.
I have put together a fairly comprehensive fiddle regarding this functionality with examples of the errors you may encounter when doing things wrong, as well as examples of several different ways you can do things correctly.
https://dotnetfiddle.net/KbJlxb
Moq uses the builder pattern, setting up the behavior of the mocks.
You can, but don't have to use the fluent interface.
Keeping that in mind, I solved the problem this way:
var sequence = myMock
.SetupSequence(""the method I want to set up"");
foreach (var item in stuffToReturn)
{
sequence = sequence.Returns(item);
}

Setup Method With Params Array

I am developing tests for an application. There's a method that has a params array as a parameter. I have set up the method using Moq but when I run the test, the return value of the method is null, which means it is not being mocked.
Here's a code sample:
public interface ITicketManager {
string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch);
}
public class TicketManager : ITicketManager {
private Queue<string> ticketQueue = new Queue<string>();
public string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch) {
var firstQueuedTicket = ticketQueue.Peek();
var firstQueuedTicketMatchesAnyOfRequested = ticketsToMatch.Any(t => t == firstQueuedTicket);
if(firstQueuedTicketMatchesAnyOfRequested)
return firstQueuedTicket;
return null;
}
}
The mock code looks like this:
var mock = new Mock<ITicketManager>();
mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string>()))
.Returns(p => {
if(p.Contains("A"))
return "A";
return null;
});
Why is it never hitting the mocked method?
You're trying to call a method taking a single string, rather than an array. Bear in mind that it's the C# compiler which handles the params part, converting calling code which just specifies individual values into a call passing in an array. As far as the method itself is concerned, it's just getting an array - and that's what you're mocking.
The compiler is actually turning your code into:
mock.Setup(m => m.GetFirstTicketInQueueIfMatches
(new string[] { It.IsAny<string>() }))
which isn't what you want.
You should use:
mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string[]>()))
If you need to verify that it only gets given a single value, you'll need to do that in the same way you would for a non-params parameter.
Basically, params only makes a difference to the C# compiler - not to moq.
I believe the params string has to be matched by It.IsAny<string[]>() rather than It.IsAny<string>()
Using Moq, the code below works to setup a callback on a method with a params argument. Defining the second argument as an array does the trick.
MockLogger
.Setup(x => x.Info(It.IsAny<string>(), It.IsAny<object[]>()))
.Callback<string, object[]>((x, y) => _length = x.Length);

Categories

Resources