Search code examples
c#unit-testingmoq

Mocking named anonymous type in C#


I am trying to mock result from my repository method so prototype of method looks like:

public IReadOnlyCollection<TResult>> Get<TResult>(IEnumerable<int> ids, Func<Model, TResult> getValues)

and execution would be:

Get<Model>(new [] { 5, 8 }, data => new { data.TimeStamp, data.Value})

What it means it gets me the record from DB and return them in a object form like TResult. If I want for example timestamp and value from table I will get just that ignoring other column Something like:

IReadOnlyCollection<{DateTime TimeStamp, double? Value}>>

Problem is I can not change this because I am not the owner of that code, so I need to figure it out how to mock it on my own. Owner uses dapper but it will have no meaning here I think.

So I try to mock this operation using Moq:

 var mock = new Mock<IModel>(MockBehavior.Strict);
    mock.Setup(
        value => value.Get(It.IsAny<int[]>(), It.IsAny<Func<Model, object>>()))
        .Returns((int _, Func<Model, object> _) =>
            Task.FromResult(new[] { _mockValue } as IReadOnlyCollection<object>));

And _mockModel is simple:

private readonly object _mockModel = new
{
    Value= 3_000_000,
    TimeStamp = DateTime.Parse("2022-12-12T16:00:00"),
};

And result is an exception:

Model.Get<{DateTime TimeStamp, double? Value}>(IEnumerable, Func<Model, {DateTime TimeStamp, double? Value}>) invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup.

Now what am I missing here?


Solution

  • As it is mentioned in comments I did not found a solution in the way I presented my problem. But I solved it, as this selector is:

    Func<Model, TResult> getValues
    

    I basically can put anything that gives me result, so instead of returning it as a anonymous object I can use some value type line named tuple so it would look like:

    Get<Model>(new [] { 5, 8 }, data => (data.Timestamp, data.Value))
    

    And result will be the same data as I would use anonymous assembly object.