1

I am writing to test an intricate class with complex nested calculations. We are looking at ActionMethod, and its returnType. The returnType is a complicated equation, how would I mock it?

var methodInfoMock  = new Mock<MethodInfo>();
var actionModel = new ActionModel(methodInfoMock.Object, new List<object>(){});

We know how to mock ActionModel, but not its returnType. So we keep it as its own variable.

If we don't know how to mock a complicated calcuation, is it Better to just keep as Own Variable, or Member of a Class?

   public void AddProducesResponseTypeAttribute(ActionModel action, Type returnType, int statusCodeResult)
   {
        if (returnType != null)
        {
            action.Filters.Add(new ProducesResponseTypeAttribute(returnType, statusCodeResult));
        }
        else if (returnType == null)
        {
            action.Filters.Add(new ProducesResponseTypeAttribute(statusCodeResult));
            }
        }
   }

See equation for returnType Below,

foreach (ActionModel action in controller.Actions)
{
     Type returnType = null;
     if (action.ActionMethod.ReturnType.GenericTypeArguments.Any())
     {
         if (action.ActionMethod.ReturnType.GenericTypeArguments[0].GetGenericArguments().Any())
         {
              returnType = action.ActionMethod.ReturnType.GenericTypeArguments[0].GetGenericArguments()[0]

;

Anyways, we have the test working, just returnType is hanging out there on its own.

Final Result:

[Theory]
[InlineData(200, typeof(IActionResult))]
[InlineData(500, typeof(IActionResult))]
public void TestAddProducesResponseType(int expectedStatusCode, Type returnType)
 {
       // Arrange
        var provider = new ProduceResponseTypeModelProvider();
        var methodInfoMock = new Mock<MethodInfo>();
        var actionModel = new ActionModel(methodInfoMock.Object, new List<object>() { });

       // Act
       provider.AddProducesResponseTypeAttribute(actionModel, returnType, expectedStatusCode);

       // Assert
       actionModel.Filters.ShouldContain(new ProducesResponseTypeAttribute(returnType, expectedStatusCode));
 }
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • 1
    Imo using `Moq` and mocking libraries is a bit of an anti-pattern, consider just writing a test implementation of the interface you're mocking out instead. – Matthew Jan 10 '20 at 20:05
  • how would I do that? –  Jan 10 '20 at 20:05
  • 1
    Can you create a private class within your unit test that has a method that matches the scenario you're testing for, and then use reflection to get the `MethodInfo` for it? – Matthew Jan 10 '20 at 20:20
  • the actionModel is really complicated, I was trying to configure it, not sure how, I've only been programming for 1 year, thats why I created a variable, so I can set it –  Jan 10 '20 at 20:21
  • 3
    @Matthew mocking is not an anti-pattern by any stretch of the imagination. –  Jan 10 '20 at 20:29
  • yeah, hearing both opinions is fine –  Jan 10 '20 at 20:29
  • 2
    Test implementations have to be constantly updated to match implementation changes. They require considerably effort compared to mocks. They don't isolate the system under test AT ALL. Its about as bad an idea as I have ever heard. This isn't the 90s, we have better ways of doing things now. Integration tests, sure you would use an actual production ready instance but not a "test implementation". For unit tests? Absolutely not. . –  Jan 10 '20 at 20:31
  • 2
    @Josh I wasn't suggesting that mocking itself is an anti-pattern, I was suggesting that using `Moq` to mock out a `MethodInfo` results in a more complicated unit test than just creating an example method that produces the required `MethodInfo`. The majority of the time I find just writing a mock implementation of an interface is much easier to read and modify than using `Moq` to stub out individual methods and try and coerce certain behaviors. – Matthew Jan 10 '20 at 20:39
  • yeah, I mean any general answer to this question would help, doesn;'t have to be specific but useful, to apply in future circumstances and career, –  Jan 10 '20 at 20:44
  • @Artportraitdesign1 The question in its current state is incomplete and therefore unclear. It would be awesome if you could reformat the question with a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) so we get a clearer picture of the current problem and what you are **actually** trying to do? – Nkosi Jan 13 '20 at 03:58

1 Answers1

1

I think I don't fully understand your specific test scenario (especially since you don't seem to be validating returnType anywhere in your tests), but since in the comments you invite more general answers, I'll outline a couple approaches that you could apply to unit-testing objects with complex internal structures (which yours seem to be).

  1. Determine the functionality you unit test and mock out everything else. Moq allows you to set up behaviours and return types of mocked objects like so:
    // Arrange
    var provider = new ProduceResponseTypeModelProvider();
    var methodInfoMock = new Mock<MethodInfo>();
    var yourKnownType = typeof(int);
    methodInfoMock.Setup(m => m.ReturnType).Returns(yourKnownType).Verifiable(); // you mock the actual property
    methodInfoMock.Setup(m => m.Filters.Add(It.IsAny<ProducesResponseTypeAttribute>())).Verifiable(); // with .Verifiable() Moq will make a note of calls to action.Filters.Add()
    var actionModel = new ActionModel(methodInfoMock.Object, new List<object>() { });

    // Act

    // Assert
    methodInfoMock.Verify(m => m.Filters.Add(It.Is<ProducesResponseTypeAttribute>(x => x.HasReturnType)), Times.Once); // checks if action.Filters.Add has been called with an instance of ProducesResponseTypeAttribute that had a returnType (i made the check up but hopefully you get the gist)
    methodInfoMock.Verify(m => m.Filters.Add(It.Is<ProducesEmptyResponseTypeAttribute>(x => x.HasReturnType)), Times.Never); // suppose ProducesEmptyResponseTypeAttribute inherits from ProducesResponseTypeAttribute and can also be passed to your mock. check it here 
    methodInfoMock.Verify(m => m.ReturnType, Times.Exactly(2)); // suppose you're expecting it to have been called twice

Then you can verify that a particular mock has been invoked and check types/values on the invocation.

  1. If the internal state is overpowering and cannot be mocked out (because, say, your behaviour depends on it), you can opt to offload some internal calculations to actual object instance that you instantiate yourself. Out of the box Moq doesn't allow you to do it, but it's possible to subclass Mock and make it wrap instances with call to actual implementation for all methods that you haven't Setup. One example of that can be found in my other SO answer. I suspect this might apply to your case if you want to mock out some bits of ActionModel while generally sticking to its implementation.
timur
  • 14,239
  • 2
  • 11
  • 32