I have the following test, with supporting classes, but I can't figure out how to verify the call on the dependency.
[TestFixture]
public class AnonymousGenericTypeParameterTests
{
[Test]
public void Test()
{
// Arrange
var dependency = new Mock<IDependency>();
var towns = new List<Town>
{
new Town { Name = "Lifford", County = "Donegal", Country="Ireland", Population = 1658 },
new Town { Name = "Ballyshannon", County = "Donegal", Country="Ireland", Population = 2504 },
new Town { Name = "Buxton", County = "Derbyshire", Country="United Kingdom", Population = 13599 },
};
var sut = new MyClass(dependency.Object);
// Act
sut.DoSomething(towns);
// Assert
// The following line needs to be fixed.
dependency.Verify(d => d.Execute(It.IsAny<IEnumerable<object>>(), It.IsAny<Func<object, decimal?>>()));
}
}
public interface IDependency
{
void Execute<T>(IEnumerable<T> collection, Func<T, decimal?> rateSelector);
}
public class MyClass
{
private readonly IDependency dependency;
public MyClass(IDependency dependency)
{
this.dependency = dependency;
}
public void DoSomething(IEnumerable<Town> towns)
{
var counties = towns.GroupBy(t => new {t.Country,t.County});
foreach (var county in counties)
{
dependency.Execute(county, c => c.Population);
}
}
}
public class Town
{
public string Name { get; set; }
public string County { get; set; }
public int Population { get; set; }
public string Country { get; set; }
}
According to Moq's test output, the performed invocations are:
Dependency.Execute(System.Linq.Lookup`2+Grouping[<>f__AnonymousType0`2[System.String,System.String],UniFocus.Staffscope4.Tests.Town], System.Func`2[UniFocus.Staffscope4.Tests.Town,System.Nullable`1[System.Decimal]])
I see plenty of questions regarding anonymous parameters in Moq (such as this and this and this), but can't find anything relating to using an anonymous type as the actual type parameter.
What can be put in the Verify line so that it actually verifies the call inside?
Note: My example IDependency
doesn't return a value (it's already complex enough, I think), but there will be bonus kudos for answers that implictly or explicitly address Setup()
as well as Verify()
.
Update
Jesse's solution only passes the test because I made a bad choice when crafting my example. I should have realised that any IGrouping<out TKey, out TElement>
is also an IEnumerable<TElement>
. Is there a more universal solution?
Update 2 I feel like my original example was possibly too elaborate and didn't represent well the actual title of my question. Is there any solution that works for this more straightforward and to-the-point example?
using Moq;
using NUnit.Framework;
namespace Tests
{
[TestFixture]
public class SimpleAnonymousGenericTypeParameterTests
{
[Test]
public void Test()
{
// Arrange
var dependency = new Mock<IDependency>();
var sut = new MyClass(dependency.Object);
// Act
sut.DoSomething("Donegal", "Lifford");
// Assert
// This verify works for both calls to Execute()
dependency.Verify(d => d.Execute(It.IsAny<object>()), Times.Exactly(2));
// This verify should specifically refer to only the first call to Execute()
dependency.Verify(d => d.Execute(It.IsAny</*HowToRepresentAnonymousTypeHere*/object>()), Times.Once);
}
public interface IDependency
{
void Execute<T>(T thing);
}
public class MyClass
{
private readonly IDependency dependency;
public MyClass(IDependency dependency)
{
this.dependency = dependency;
}
public void DoSomething(string county, string town)
{
dependency.Execute(new { county, town });
object someUnknownObject = "";
dependency.Execute(someUnknownObject);
}
}
}
}
The accepted answer doesn't work for me, I believe it's because the tests and the object in question are in a different assembly so Moq doesn't know how to reconcile the types and does not match them.
Instead, I created the following helper methods that can verify that the anonymous type provided has the correct fields and values:
public static class AnonHelpers
{
public static object MatchAnonymousType(object expected)
{
return Match.Create(Matcher(expected));
}
private static Predicate<object> Matcher(object expected)
{
return actual =>
{
var expectedProp = expected.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(expected));
var actualProp = actual.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(actual));
foreach (var prop in expectedProp)
{
if (!actualProp.ContainsKey(prop.Key))
return false;
if (!prop.Value.Equals(actualProp[prop.Key]))
return false;
}
return true;
};
}
}
They can be used like so:
var anon = new { SomeKey = "some value", SomeOtherKey = 123 };
myMock.Setup(x => x.MyMethod(personIDs, AnonHelpers.MatchAnonymousType(anon))).Verifiable();
This will create a matcher that will use reflection to match the anonymous type based on it's keys and values and then you can use normal verification to see when it's been called.
Since the types are known in the context of the test, you could provide the specific type arguments to the Verify call. The following change got the test to pass:
dependency.Verify(d =>
d.Execute(It.IsAny<IEnumerable<Town>>(), It.IsAny<Func<Town, decimal?>>()));
The same should also work for setups.
With regards to the example in Update 2, the following passes, but it requires knowledge of the inner workings of the DoSomething()
method and as far as I know it's the only way to make it work:
var anonymousType = new {county = "Donegal", town = "Lifford"};
dependency.Verify(d => d.Execute(anonymousType), Times.Once);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With