Moq Verify with anonymous type parameter - c#

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

Related

Generic class and method binding with delegates(or not) for clean method expression

Lets say you have simple chained method but you are trying to access or set a value in a class property (internal/external doesnt matter). Using a Func seems to be working and finds the relation between generic class that is passed and access its properties correctly but i am not sure if its necessary.
Is there a way of setting the method variable cleanly as in Main method below since it is aware of the Generic class association without doing new Props().Property for example?
//sample console app
public class Props {
public string FirstProp = "lets say object";
public string SecondProp = "Pretend some other object";
}
public class Logic<T> where T : class, new()
{
private string outString { get; set; }
public Logic<T> GetPropertyValue(Func<T, object> propertySelector)
{
return this;
}
public Logic<T> GetLambda(Expression<Func<T, object>> propertySelector)
{
var breakpointCheck = propertySelector; //{x => x.SecondProp}
return this;
}
}
class Program
{
static void Main(string[] args)
{
var Test =
new Logic<Props>()
.GetPropertyValue(x => x.FirstProp) //dummy check
.GetLambda(x => x.SecondProp); //passed correctly {x => x.SecondProp}
var HowToGetThis =
new Logic<Props>()
.GetPropertyValue(FirstProp) // or GetPropertyValue(Props.FirstProp)
.GetLambda(x => x.SecondProp);
}
}

How to use Bogus Faker with initialization properties?

I have an immutable DTO that I'd like to fake with Bogus Faker (version 31.0.2) but the property with an overriding rule only returns what it was initialized with by the constructor:
Example DTO (real ones are more complex)
using Xunit;
using Bogus;
namespace SO.Tests
{
class ClassWithInitialization
{
public ClassWithInitialization(string name)
{
this.Name = name
}
public string Name { get; }
}
Example DTO Faker
class FakeClassWithInitialization : Faker<ClassWithInitialization>
{
private FakeClassWithInitialization() { }
public static CreateDefault()
{
return (FakeClassWithInitialization) new FakeClassWithInitialization()
.CustomInstantiator(f => new ClassWithInitialization(null))
.RuleFor(o => o.Name, f => f.Person.FullName);
}
public FakeClassWithInitialization WithName(string name)
{
RuleFor(o => o.Name, f => name);
return this;
}
}
Example Tests
Both of the following tests fail as the Name property remains null as provided in the constructor.
public class Tests
{
[Fact]
public void TestClassWithInitialization()
{
var faker = FakeClassWithInitialization
.CreateDefault();
var testPoco = faker.Generate();
Assert.False(string.IsNullOrEmpty(testPoco.Name)); #fails
}
[Fact]
public void TestClassWithInitialization_with_overriding_rule()
{
var faker = FakeClassWithInitialization
.CreateDefault()
.WithName("John Smith");
var testPoco = faker.Generate();
Assert.AreEqual("John Smith", testPoco.Name); #fails
}
}
}
Although I could use Faker to generate random data for the constructor I would like to be able to use this fake instance to generate alternative versions, for instance, with a fixed Name as exampled by the second test above.
Why is this not working and are there any known workarounds?
Note: this is not the same as the question How can I use Bogus with private setters
It is possible but I'd advise against it because the solution relies on .NET's Reflection.
There's a new Faker<T>(binder:...) binder constructor parameter. The IBinder interface is what Faker<T> uses to reflect over T to discover properties and fields that are settable. Whatever IBinder.GetMembers(Type t) returns is what Faker<> sees in T.
With this information, let's look at how the compiler generates an object with a public parameterized constructor and read-only property:
public class Foo
{
public Foo(string name){
this.Name = name;
}
public string Name { get; }
}
The C# compiler generates:
public class Foo
{
// Fields
[CompilerGenerated, DebuggerBrowsable((DebuggerBrowsableState) DebuggerBrowsableState.Never)]
private readonly string <Name>k__BackingField;
// Methods
public Foo(string name)
{
this.<Name>k__BackingField = name;
}
// Properties
public string Name => this.<Name>k__BackingField;
}
The storage for the Foo.Name property uses a backing field called Foo.<Name>k__BackingField. This backing field is what we need IBinder to hoist into Faker<>. The following BackingFieldBinder : IBinder does this:
public class BackingFieldBinder : IBinder
{
public Dictionary<string, MemberInfo> GetMembers(Type t)
{
var availableFieldsForFakerT = new Dictionary<string, MemberInfo>();
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
var allMembers = t.GetMembers(bindingFlags);
var allBackingFields = allMembers
.OfType<FieldInfo>()
.Where(fi => fi.IsPrivate && fi.IsInitOnly)
.Where(fi => fi.Name.EndsWith("__BackingField"))
.ToList();
foreach( var backingField in allBackingFields){
var fieldName = backingField.Name.Substring(1).Replace(">k__BackingField","");
availableFieldsForFakerT.Add(fieldName, backingField);
}
return availableFieldsForFakerT;
}
}
Customize the GetMembers() method above to suit your needs. You'll need to change the code if you want to include public fields or properties of T too.
The last problem we have to solve is creating an object without specifying constructor arguments. We can do this by using .GetUninitializedObject() from FormatterServices or RuntimeHelpers. To do this, we'll create an extension method that extends the Faker<T> API as shown below:
public static class MyExtensionsForFakerT
{
public static Faker<T> SkipConstructor<T>(this Faker<T> fakerOfT) where T : class
{
return fakerOfT.CustomInstantiator( _ => FormatterServices.GetUninitializedObject(typeof(T)) as T);
}
}
With these two components in place, we can finally write the following code:
void Main()
{
var backingFieldBinder = new BackingFieldBinder();
var fooFaker = new Faker<Foo>(binder: backingFieldBinder)
.SkipConstructor()
.RuleFor(f => f.Name, f => f.Name.FullName());
var foo = fooFaker.Generate();
foo.Dump();
}
public class Foo
{
public Foo(string name)
{
this.Name = name;
}
public string Name {get;}
}
You can find a full working example here. Additionally, you may find other solutions in Issue 213 helpful.
I just tried this and it seems to work :
class FakeClassWithInitialization : Faker<ClassWithInitialization>
{
private FakeClassWithInitialization() { }
public static FakeClassWithInitialization CreateDefault()
{
return (FakeClassWithInitialization) new FakeClassWithInitialization()
.CustomInstantiator(f => new ClassWithInitialization(f.Person.FullName));
}
}
I used directly the class constructor with the generator instead of using the generator with the property.
I also remove the WithName method that was not used.
Edit : Seems I misunderstood the question.
I don't know much about Bogus. I thought you could use optional parameters in "CreateDefault" method but you told DTO was complex so... There will be too much parameters.
I think you can achieve what you want with the builder pattern :
public class Builder
{
private string _name;
public Builder WithName(string name)
{
_name = name;
return this;
}
public ClassWithInitialization Build()
{
return new Faker<ClassWithInitialization>()
.CustomInstantiator(f =>
new ClassWithInitialization(
_name ?? f.Person.FullName
))
.Generate();
}
}
var faker = new Builder().WithName("Hello").Build();
var faker2 = new Builder().Build();
You can delete the FakeClassWithInitialization and replace it with a classic "Builder".

How does Moq verify Generic Func Parameter?

Given
public interface IService
{
void Run<T>(T value, Func<T, string> func);
}
public class Sut
{
private readonly IService m_service;
public Sut(IService service)
{
m_service = service;
}
public void Test()
{
Point point = new Point {X = 1, Y = 2};
m_service.Run(point, p => $"X:{p.X}, Y:{p.Y}");
}
}
internal class Point
{
public int X { get; set; }
public int Y { get; set; }
}
And tested like
[Test]
public void RunTest()
{
// Arrange
Mock<IService> mockService = new Mock<IService>();
var sut = new Sut(mockService.Object);
// Act
sut.Test();
// Assert
mockService.Verify(e => e.Run(It.IsAny<It.IsAnyType>(), It.IsAny<Func<It.IsAnyType, string>>()), Times.Once);
}
This test will failed, due to Point is third party internal class, I can not use It.IsAny<Point> in the verify.
if I change the Point to the public and verify use following, it's working good.
mockService.Verify(e => e.Run(It.IsAny<Point>(), It.IsAny<Func<Point, string>>()), Times.Once);
any help would be appreciated
Generally, you want to put an InternalsVisibleTo attribute in the assembly under test, pointing to the test assembly.
See here for reference information.

Override Autofixture customization setup

I've a class with several services injected in its constructor. I'm using Autofixture with xUnit.net and NSubstitute, and created an attribute to setup the global customization.
public class AutoDbDataAttribute : AutoDataAttribute
{
public AutoDbDataAttribute() : base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
{
}
public AutoDbDataAttribute(Type customizationType) : base(() =>
{
var customization = Activator.CreateInstance(customizationType) as ICustomization;
var fixture = new Fixture();
fixture.Customize(new AutoNSubstituteCustomization());
fixture.Customize(customization);
return fixture;
})
{
}
}
I also have a custom customization class that setups the common customization for the test methods in the same class.
public class RevenueProviderCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<IRevenueContextService>(() =>
{
var contextService = Substitute.For<IRevenueContextService>();
contextService.GetContext().Returns(fixture.Create<RevenueContext>());
return contextService;
});
fixture.Register<ICompanyService>(() =>
{
var companyService = Substitute.For<ICompanyService>();
companyService.Get(Arg.Any<Guid>()).Returns(fixture.Create<Company>());
return companyService;
});
}
}
Now, some of my tests depend on modifying specific properties in the objects returned by the services. So in some cases, I want to modify the RevenueContext and in some cases, I want to modify the Company data.
What I did was creating another object inside the test itself and modify the Returns of the service with the new object, like this:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(RevenueProvider sut, Company company, [Frozen]IRevenueContextService contextService)
{
var fixture = new Fixture();
RevenueContext context = fixture.Build<RevenueContext>().With(c => c.DepartmentId, null).Create();
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
But this doesn't work. The RevenueContext from the RevenueProviderCustomization is still used.
Does anyone know how I can override the return from the service? I don't want to setup the fixture one by one in my test, so I was hoping to be able to create a 'general setup' and modify as needed according to the test case.
UPDATE 1
Trying the answer from Mark, I changed the test to
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue([Frozen]IRevenueContextService contextService, [Frozen]Company company, RevenueProvider sut, RevenueContext context)
{
context.DepartmentId = null;
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
The problem is because the RevenueContext is called in the RevenueProvider constructor. So my modification to the DepartmentId happens after the call was made.
public RevenueProvider(IRevenueContextService contextService, ICompanyService companyService)
{
_contextService = contextService;
_companyService = companyService;
_company = GetCompany();
}
public double GetRevenue()
{
if (_hasDepartmentContext)
return _company.Departments.Single(d => d.Id == _departmentId).Revenue;
else
return _company.Revenue;
}
private Company GetCompany()
{
RevenueContext context = _contextService.GetContext();
if (context.DepartmentId.HasValue)
{
_hasDepartmentContext = true;
_departmentId = context.DepartmentId.Value;
}
return _companyService.Get(context.CompanyId);
}
Assuming that RevenueProvider essentially looks like this:
public class RevenueProvider
{
private readonly ICompanyService companySvc;
public RevenueProvider(ICompanyService companySvc)
{
this.companySvc = companySvc;
}
public object GetRevenue()
{
var company = this.companySvc.Get(Guid.Empty);
return company.Revenue;
}
}
Then the following test passes:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(
[Frozen]ICompanyService companySvc,
RevenueProvider sut,
Company company)
{
companySvc.Get(Arg.Any<Guid>()).Returns(company);
var actual = sut.GetRevenue();
Assert.Equal(company.Revenue, actual);
}
This scenario is exactly what the [Frozen] attribute is designed to handle. The various attributes that AutoFixture defines are applied in the order of the arguments. This is by design, because it enables you to pull out a few values from the argument list before you freeze a type.
In the OP, [Frozen] is only applied after sut, which is the reason the configuration of the mock doesn't apply within the SUT.

Using Moq to verify a method call on class in a collection

I'm not sure if I'm using Moq the right way, so if anyone could help, I'd be grateful.
I want to test the call of Clone() method on object in a collection. The test looks like this:
[Test]
public void CloneTest()
{
var mdFake = new Mock<MachineDecision>();
var clonable = mdFake.As<ICloneable>();
clonable.Setup(x => x.Clone()).Verifiable();
var decision = new Decision()
{
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
var newDecision = (Decision) decision.Clone();
clonable.Verify(x => x.Clone());
}
The test fails: Moq.MockException :
Expected invocation on the mock at least once, but was never performed: x => x.Clone() but I believe it should actually pass.
Used classes look as follows:
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item => (MachineDecision) item.Clone()).ToList();
}
return obj;
}
}
public class MachineDecision : Entity<Guid>, ICloneable
{
//...
}
There are two options available.
First, you can make an implementation of method Clone() virtual and your test will be 'Green'
public class MachineDecision : Entity<Guid>, ICloneable
{
public virtual object Clone()
{
throw new NotImplementedException();
}
}
Second, you can invoke Clone() method from ICloneable interface: (MachineDecision)(item as ICloneable).Clone(); and your test will be 'Green' also.
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item =>
{
return (MachineDecision)(item as ICloneable).Clone();
}).ToList();
}
return obj;
}
}
I realise that now it is not the best code but it is up to you how to refactor it further.
I'd do it like this:
[Test]
public void CloneTest()
{
// create the mock
var mdFake = new Mock<MachineDecision>();
var decision = new Decision
{
// setup (pass it to my collection)
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
// call the method being tested (you need to make Clone() virtual)
decision.Clone();
// check for the side effects -> It was called once !
mdFake.Verify(x => x.Clone(), Times.Once());
}
I hope this helps you.
EDIT - I'm sorry, as it was pointed in the comments - I forgot to mention, that what I'm suggesting requires you to make Clone() (in MachineDecision) - virtual, which might not be ideal in your case.
Try this:
...
clonable.Expect(x => x.Clone()).Verifiable().Returns(null);
...
clonable.Verify();

Categories