Moq the result that depends on input - c#

I am a bit confused on Moq call. I need to Moq a function that takes an object. It should return a different object, whose content is generated by an existing function, that takes its input from field of the input object.
So I supply a complex object in input, and one of its fields is equal to some number, and I need to reply with object that is generated taking into account that some number.
I came up with the following sketch but it is full of errors. I appreciate a proper primer how to do what I need.
var processor = new Mock<IMyCommandProcessor>();
processor.Setup(d => d.ProcessCommand(It.IsAny<MyCommand>))
.Returns((MyResponse r) => r.Results = new List{ newDto(aaa) });
newDto(aaa) is the call of a function, and instead of aaa I need a field that comes from MyCommand object given from input. How I can declare mocking here? Thanks a lot!

If newDto(aaa) is a call to a helper function then you could try:
processor.Setup(d => d.ProcessCommand(It.IsAny<MyCommand>))
.Returns((MyCommand c) => new MyResponse(){ Results = new List<DtoType>(){ newDto(aaa)}});

Just a generic example :
you can replace input + input with any method of course.
[Test]
public void TestMock()
{
var a = new Mock<IDictionary<string, string>>();
a.Setup(d => d[It.IsAny<string>()]).Returns((string input) => input + input);
string result = a.Object["test"];
}

You should use input parameters in Returns callback:
processor.Setup(d => d.ProcessCommand(It.IsAny<MyCommand>))
.Returns((MyCommand c) => new MyResponse()});
However you cannot access the newDto function if it's defined on the class you are testing.

Related

Moq - Generic set up don't return expected value

I am new to Moq, here I have two setups.
var settingsMock = new Mock<IECSConfigSettings>();
settingsMock.Setup(m => m.GetRootValue("ss", It.IsAny<string>())).Returns("aaa");
And another one is
private static void BuildSettingCacheForMock<T>(Mock<IECSConfigSettings> mock, string key, T value)
{
mock.Setup(m => m.GetRootValue<T>(key, It.IsAny<T>())).Returns(value);
mock.Setup(m => m.GetValue<T>(key, It.IsAny<T>())).Returns(value);
mock.Setup(m => m.TryGetValue<T>(key, out value)).Returns(true);
mock.Setup(m => m.TryGetRootValue<T>(key, out value)).Returns(true);
}
var settingsMock = new Mock<IECSConfigSettings>();
BuildSettingCacheForMock<string>(settingsMock, "sss", "aaa1");
Finally when I invoke both of them
var s1 = new SettingsETag(settingsMock.Object, etag: "ETag", null).Settings.GetRootValue("ss"); // gives "aaa"
var s2 = new SettingsETag(settingsMock.Object, etag: "ETag", null).Settings.GetRootValue("sss"); // gives null
Interface details
Interface code
I do not know what is the differences between these and why the result for the second one is null. Appreciate your thoughts on this!
You have set up a return value for the specific call settingsMock.Setup(m => m.GetRootValue("ss", It.IsAny<string>())).Returns("aaa"); - that is when called with the key "ss", no other values. The second call does not have a set up return value, so you get the default return value null.
In general I think it helps to create mocks with MockBehavior.Strict. This gives you information about unexpected calls when running your unit tests. The constructor looks like this;
var settingsMock = new Mock<IECSConfigSettings>(MockBehavior.Strict);
If you want to return the same value regardless of the parameter value you can use It.IsAny<string>() for the first parameter too.
settingsMock.Setup(m => m.GetRootValue(It.IsAny<string>(), It.IsAny<string>())).Returns("aaa");

Why C# Xunit Mock returning empty enumeration on IQueryable

trying to mock one method in repository which having return IQueryable.
Please see the unit test method
[Fact]
public void TestMethod()
{
var mockZonal = new Mock<IBaseRepository<ZonalDefinition>>().SetupAllProperties();
var list = new List<ZonalDefinition>() { new ZonalDefinition() { DestinationZone = "401" } }.AsQueryable();
mockZonal.Setup(r => r.GetQueryableFromSql<ZonalDefinition>(new SqlQuerySpec(), new FeedOptions())).Returns(()=>list);
_repoFactory.Setup(r => r.GetGenericRepository<ZonalDefinition>(It.IsAny<string>(), It.IsAny<string>())).Returns(mockZonal.Object);
var afShipmentDetail = new AirFreightShipmentDetail();
var response = _quoteRespository.SetCXShipmentTargetValue(afShipmentDetail);
Assert.NotNull(response);
}
while executing the test am getting the result for mocked method 'GetQueryableFromSql' as 'Enumeration yielded no results'
enter image description here
As far as I understand Moq, you have to setup your method differently:
mockZonal.Setup(r => r.GetQueryableFromSql<ZonalDefinition>(It.IsAny<SqlQuerySpec>(),
It.IsAny<FeedOptions>()))
.Returns(()=>list);
The way you set it up, it would only match if those exact objects were passed to the method (which they won't).
If you need to be more specific with regards to the parameters to match, have a look at the documentation.

Need "Method return type" of data selected with LINQ from DataTable

I have a method, which takes data received from database, and it takes only data which has a specific day:
private static **return type** FilterDataByDay(DataTable dt, string nameOfTheDay)
{
var data = dt.AsEnumerable().Select(x => new
{
code = x.Field<string>("Code"),
day= x.Field<string>("Day"),
name= x.Field<string>("Name"),
startTime= x.Field<int>("StartTime"),
endTime= x.Field<int>("EndTime")
})
.Where(x => x.day.Equals(nameOfTheDay))
.ToList();
return data ;
}
The problem is I don't know how to return data from this method, that other method could take it ant print it out, every element like of each row, it should let me print something like:
foreach(var variable in "the retuned data from method")
{
Console.WriteLine(variable.code +" "+ variable.day + ..etc...
}
The thing about anonymous types is that they're not named, e.g. anonymous.
The best course of action is to define your own class with the appropriate properties after which you can return IEnumerable<SomeClass>.
You could create a Wrapper class and then you'll have IEnumerable<MyClass>
or you can use IEnumerable<dynamic> , but this way - you wont have intellisence.
Defining a proper class that would encapsulate the loaded data is probably the best way to go. But if you are dealing with data you will not need later and you don't pass them to much around, you can leverage the Tuple class. It will look slightly awkward, but if it is just your code and it is not a part of a public API then it is also usable.
Your return type would then be IEnumerable<Tuple<string, string, string, int, int>>

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