Using Moq to set indexers in C# - c#

I'm having trouble figuring out how to set indexers in C# with Moq. The Moq documentation is weak, and I've done a lot of searching... what I'd like to do is similar in the solution to How to Moq Setting an Indexed property:
var someClass = new Mock<ISomeClass>();
someClass.SetupSet(o => o.SomeIndexedProperty[3] = 25);
I want to modify the above to work for any index and any value so I can just do something like this:
someClass.Object.SomeIndexedProperty[1] = 5;
Currently I have the following, which works great for the indexed property getter, but if I ever set the value Moq ignores it:
var someValues = new int[] { 10, 20, 30, 40 };
var someClass = new Mock<ISomeClass>();
someClass.Setup(o => o.SomeIndexedProperty[It.IsAny<int>()])
.Returns<int>(index => someValues[index]);
// Moq doesn't set the value below, so the Assert fails!
someClass.Object.SomeIndexedProperty[3] = 25;
Assert.AreEqual(25, someClass.Object.SomeIndexedProperty[3]);

I found a solution to my problem. It requires a shift in my thinking... I had been looking to use NUnit's Assert to verify that the indexer setter in my someClass mock was being called with the correct value.
It seems that with Moq the supported way to do this is to use the VerifySet function. A contrived example:
someClass.Object.SomeIndexedProperty[3] = 25;
someClass.VerifySet(mock => mock.SomeIndexedProperty[3] = 25);
The unit test passes since SomeIndexedProperty[3] is set to 25, but would fail otherwise.

Using Moq 3.1.416.3
Setup won't work for indexers (because it takes an expression which means assignment statements are ruled out)
so you need to use SetupSet like
_settingsStore.SetupSet(store => store["MruNotes"] = It.IsAny<string>())
.Callback<string,string>( (key, value) => persistedValue = value);
A small caveat:
this expression only matches if the key is "MruNotes". I was not able to use a matcher like It.IsAny for the key.

In your test your only set expectations for the getter of the indexer - and this will always return the corresponding value from your array. The indexer doesn't behave like a real thing. You can try a few things to have it fixed:
You can check if you can stub this indexer. I am personally using RhinoMocks, so I have no idea if this is implemented
someClass.SetupProperty(f => f.SomeIndexedProperty);
You can try to mock the setter as well and make it to change the underlying array. My first guess would be to try something along these lines (no guarantee it will work):
someClass.Setup(o => o.SomeIndexedProperty[It.IsAny<int>()] = It.IsAny<int>())
.Callback((index, value) => someValues[index] = value);
Or if the ISomeClass interface is small enough, you could just created a stub implementation yourself (that would have the indexer implemented as a dictionary, array etc.)

Related

Passing value in Mock Rhino test

I have following code:
if (ActiveApplication.GetField("previous_date").Value != ActiveApplication.GetField("new_date").Value)
{
//do something..
}
I want to unit test this. Being new to Rhino tests, I am trying to figure out how to pass value so that i go in the loop. Here is what i have tried:
var previous_date = MockRepository.GenerateMock<IField>();
stubApplication.Stub(x => x.GetField("previous_date")).Return(previous_date);
previous_date.Stub(x => x.GetInternalValue()).Return("20160525");
var new_date = MockRepository.GenerateMock<IField>();
stubApplication.Stub(x => x.GetField("new_date")).Return(new_date);
new_date.Stub(x => x.GetInternalValue()).Return("20160525");
Can someone please tell me what am i doing wrong?
This returns previous_date, an interface of type IField:
stubApplication.Stub(x => x.GetField("previous_date")).Return(previous_date)
Because it's not a base class implementation, your code uses the Value property on the interface which has to be setup in a mock as well, rather than using GetInternalValue(). Same with new_stub.
EDIT: You need essentially to do the following (note I'm not sure if this is the correct syntax as I haven't used that framework, but I'm trying to capture the essence):
previous_date.Stub(x => x.Value).Return("20160525");

How to effectively test SiteCore LinkField

I have been using moles to write unit tests on the hard to reach parts of my code – particularly where I use the types found in the sitecore class libraries (which are hard to use mocking frameworks with). I have come across a surprisingly tricky problem where I’m trying to mole a LinkField type and test the following kind of code snippet.
LinkField linkField = item.Fields["External Url"];
if (linkField.IsInternal && linkField.TargetItem != null)
{
// want to test this path
item.Fields is a field collection whose indexer returns a type of SiteCore.Data.Field, but LinkField is set up such that uses an implicit operator which hides the conversion which means you are able to work with an instance of LinkField in your code.
My difficulty is that I cannot create a mole of type MLinkField, and assign this to the FieldCollection in the Item as it is strongly typed to Field. Moreover, it seems that whilst I am able to create a type of MField, when the implicit conversion happens, it will work and return an object but none of the fields are set to have any values. This means, I can’t test the code path above which relies on the state of the linkField being set a certain way.
The only way I can think of setting these values is indirectly – i.e. finding what values need to be set by analysing the implicit conversion and setting these in MField. The implicit operator calls the LinkField constructor as follows:
public LinkField(Field innerField) : base(innerField, "link")
which means I need to be conscious of how it instantiates the base type (XmlField), and in turn that class’s base type (CustomField).
Then, to look at what underlying values TargetItem is looking for. The end result is the need to mole out:
InnerField.Database.Items[internalPath];
Or
InnerField.Database.Items[targetID];
Where InnerField is effectively my MField.
Does anyone have a better idea? This sounds horribly convoluted but I think that’s the nature of the beast with these assemblies.
It can be done but you'll need to jump through a few hoops to make it work.
First of all, a bit of background:
LinkField does not inherit from the Field class like some other field types do.
LinkField inherits from XmlField which in turn inherits from CustomField.
CustomField (and it's subtypes) are instantiated by passing a field instance into the constructor.
Linkfields store their values in this field instance.
Linkfields cannot be added to a FieldCollection as they do not inherit from Field.
Rather than add the LinkField we need to add the LinkField's InnerField property.
When a Field is pulled from a FieldCollection and assigned to a LinkField an implicit conversion operation is performed.
The implicit conversion operation creates a new LinkField by passing the selected field to the LinkField's constructor. It is this new LinkField that is returned.
Now some code:
const string externalUrl = "External Url";
const string targetItemName = "Target Item";
Field field = new ShimField { IDGet = () => ID.NewID, NameGet = () => externalUrl };
Item targetitem = new ShimItem { IDGet = () => ID.NewID, NameGet = () => targetItemName };
LinkField linkfield = new ShimLinkField(field) { IsInternalGet = () => true, TargetItemGet = () => targetitem };
ShimLinkField.ImplicitOpFieldLinkField = (f) => linkfield;
FieldCollection fields = new ShimFieldCollection { ItemGetString = (name) => linkfield.InnerField };
Item item = new ShimItem { NameGet = () => "Test Item", FieldsGet = () => fields };
And now for a bit of explanation:
The key to making the above code work is the line:
ShimLinkField.ImplicitOpFieldLinkField = (f) => linkfield;
By Shimming the implicit conversion operator, we can ensure that when the following line is called:
LinkField linkField = item.Fields["External Url"];
A link field is returned and it's properties are shimmed as you want them.
Since LinkField cannot be mocked in a proper way it have to be used in unit tests "as is" meaning that you'll have to test both your code and the link field implementation.
The good news is that the Link field is an XmlField that operates with the xml data stored in the inner field value. In order to configure the link field behavior you just need to set proper xml in the value.
With Sitecore.FakeDb you can easily create content in memory and configure items and fields you need. The following code creates items home and target. The home item has got Url link field which has TargetId pointed to the target item:
ID targetId = ID.NewID;
using (var db = new Db
{
new DbItem("home")
{
// Field 'Url' is an internal link which targets the 'target' item
{ "Url", "<link linktype=\"internal\" id=\"{0}\" />".FormatWith(targetId) }
},
new DbItem("target", targetId)
})
{
Item item = db.GetItem("/sitecore/content/home");
LinkField linkField = item.Fields["Url"];
linkField.IsInternal.Should().BeTrue();
linkField.TargetItem.Should().NotBeNull();
linkField.TargetItem.Paths.FullPath.Should().Be("/sitecore/content/target");
}
Personally speaking, I do try to abstract Sitecore away from business logic that doesn't need to interact with it directly; however I'm mindful that some things will need to deal with it directly and I try not to take it too far. If you spend too much time abstracting Sitecore out of your logic, then in my opinion you can end up making it more difficult to take advantage of some features that make Sitecore useful.
While unit testing purists may disagree with my approach, I will have unit tests that use the Sitecore API to properly instantiate items. Doing so is fairly straight-forward, I wrote a blog post about it a while ago. Then your only problem is dealing with test data, but it's fairly easy to create it with a test set-up and remove it with a test tear-down.

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);
}

Rhino Mock List constraint

I'm trying to asssert that a method was called on a stub. The method I'm trying to assert was called takes an IEnumerable<string>. I don't care about the exact contents, but I just want to test that the count is a certain number. I can't get the assertion correct, I get
Rhino.Mocks.Exceptions.ExpectationViolationException : Bob.DoThings(collection count equal to 10); Expected #1, Actual #0.
I know that DoThings() is indeed being called... I just can't get the constraint correct..
var myBob= MockRepository.GenerateStub<Bob>();
var countConstraint = Rhino.Mocks.Constraints.List.Count(Rhino.Mocks.Constraints.Is.Equal(10));
// execution code....
Joe myJoe = new Joe(myBob);
myJoe.MethodThatShouldCallDoThingWith10();
myBob.AssertWasCalled(s => s.DoThings(null), o => Constraints(countConstraint));
I've also tried adding "IgnoreArguments" as a constraint. What am I missing?
The issue here is with deferred execution. It's not until the IEnumerable<string> is enumerated that the list of items is "built". Since Rhino.Mocks just records what gets called, it never "uses" the method arguments and therefore, the list is never built nor enumerated. As you've seen, adding a ToList() or ToArray() enumerates and builds the list so the test will pass if you use one of those methods.
One workaround is to grab the list that was passed to the method and do your check on that:
var list = (IEnumerable<int>) myBob.GetArgumentsForCallsMadeOn(b => b.DoThings(null))[0][0];
Assert.AreEqual(10, list.Count());
This test passes and doesn't require any changes to your code.
This problem was alredy reported Here. I've been able to reproduce this problem with the following Bob and Joe:
public interface Bob
{ void DoThings(IEnumrable<int> list); }
public class Joe
{
private readonly Bob bob;
public Joe(Bob bob)
{ this.bob = bob; }
public void MethodThatShouldCallDoThingWith10()
{
var values = Enumerable.Range(1, 100).Where(x => x > 0 && x < 11);
bob.DoThings(values);
}
}
It seems there's some problem in Rhino Mocks after all, when it comes to LINQ: either report the bug to Ayende or add ToList() in your production code (not really recommended)...

Stubbing a property twice with rhino mocks

For some objects I want to create default stubs so that common properties contains values. But in some cases I want to override my default behaviour. My question is, can I somehow overwrite an already stubbed value?
//First I create the default stub with a default value
var foo = MockRepository.GenerateStub<IFoo>();
foo.Stub(x => x.TheValue).Return(1);
//Somewhere else in the code I override the stubbed value
foo.Stub(x => x.TheValue).Return(2);
Assert.AreEqual(2, foo.TheValue); //Fails, since TheValue is 1
Using Expect instead of Stub and GenerateMock instead of GenerateStub will solve this:
//First I create the default stub with a default value
var foo = MockRepository.GenerateMock<IFoo>();
foo.Expect(x => x.TheValue).Return(1);
//Somewhere else in the code I override the stubbed value
foo.Expect(x => x.TheValue).Return(2);
Assert.AreEqual(1, foo.TheValue);
Assert.AreEqual(2, foo.TheValue);

Categories

Resources