Search code examples
c#unit-testingtddrhino-mocksanonymous-types

Unit testing a Response RedirectToRoute that returns an anonymous type


I am testing an HttpModule in an AspNet MVC application using HttpResponseBase objects as suggested by Kazi Rashid's blog

In my code under test I have:

context.Response.RedirectToRoute(new { Controller = "C1", Action = "A1" });

In my Unit Test (using RhinoMocks in a separate Test Project), I can get the actual argument passed to this method using:

var actual = this.ResponseMock.GetArgumentsForCallsMadeOn(r => r.RedirectToRoute(new { Controller = "dummy", Action = "dummy" }),
            options => options.IgnoreArguments())[0][0];

And I can create my expected argument in the test as:

var expected = new {Controller = "C1", Action = "A1" };

When I run this test, all looks very promising. If I put both "actual" and "expected" in the Watch window, I can see that their values look identical, and that their anonymous types look identical too.

But, when it comes to the Assert, Visual Studio just can't see the properties on the Actual so I can't actually type my Assert. If I type the following:

actual.Controller =

Visual Studio just says:

Can't resolve the symbol 'Controller'

I have tried the solutions recommended for casting to anonymous types (e.g. cast-to-anonymous-type, but this just throws the following exception:

{"[A]<>f__AnonymousType02[System.String,System.String] cannot be cast to [B]<>f__AnonymousType02[System.String,System.String]. Type A originates from '^My Assembly Under Test^, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location '^MyAssemblyUnderTest.dll^'. Type B originates from '^My Test Assembly^, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location '\^MyTestAssembly.dll^'."}

I have tried to use Reflection to copy the properties from 'actual' to a new anonymous type, but that fails too. Just wish I knew how my Watch window was able to do it....

So, what I'm after is:

  • Ideally, the preferred way to perform an Assert on my 'actual' to show that it's properties are as expected
  • Or, a way to cast my 'actual' into something I can read.

Thanks in advance

Griff


Solution

  • Finally solved it...the answer was on stackoverflow (where else?) C# ‘dynamic’ cannot access properties from anonymous types declared in another assembly

    To summarize:

    Class under test (HttpModule Assembly)

    context.Response.RedirectToRoute(new { Controller = "C1", Action = "A1" });
    

    Test Class (HttpModuleTest Assembly)

    var actual = this.ResponseMock
        .GetArgumentsForCallsMadeOn(r => 
            r.RedirectToRoute(new { Controller = "dummy", Action = "dummy" }),
                options => options.IgnoreArguments())[0][0];
    
    var controllerProperty = properties.Find("Controller", false);
    var actionProperty = properties.Find("Action", false);
    
    var controllerProperty = properties.Find("Controller", false);
    var actionProperty = properties.Find("Action", false);
    
    string controllerValue = controllerProperty.GetValue(actual).ToString();
    string actionValue = actionProperty.GetValue(actual).ToString();
    

    Then you are in a position to perform you Assert.