Reputation: 41991
I'm interested in using Steve Sanderson’s MvcIntegrationTestFramework or a very similar alternative with ASP.NET MVC 3 Beta.
Currently when compiling MvcIntegrationTestFramework against MVC 3 Beta I get the following error due to changes in MVC:
Error 6
'System.Web.Mvc.ActionDescriptor.GetFilters()' is obsolete: '"Please call System.Web.Mvc.FilterProviders.Providers.GetFilters() now."'
\MvcIntegrationTestFramework\Interception\InterceptionFilterActionDescriptor.cs Line 18
--- and / or ---
EDIT #1: Note I have e-mailed Steve the creator of MvcIntegrationTestFramework, also hoping for some feedback there.
EDIT #2 & #3: I have received a message from Steve. Quoted for your reference:
I haven't needed to use that project with MVC 3, so sorry, I don't have an updated version of it. As far as I'm aware it should be possible to update it to work on MVC 3, but you'd need to figure that out perhaps by inspecting the MVC 3 source code to notice any changes in how actions, filters, etc are invoked now. If you do update it, and if you decide to adopt it as an ongoing project (e.g., putting it on Github or similar), let me know and I'll post a link to it! (Thanks Steve!)
EDIT #4: Honestly had a quick stab at using System.Web.Mvc.FilterProviders.Providers.GetFilters()
didn't get anywhere fast and simply adding the [Obsolete]
found that there was an error in the internals of the MVC requests. Anybody else had a dabble?
EDIT #5: Please comment if you are using an alternative Integration Test Framework with MVC 3.
Upvotes: 18
Views: 2570
Reputation: 5467
I thought I would share my experiences with using MvcIntegrationTestFramework in an ASP.NET MVC 4 project. In particular, the ASP.NET MVC 4 project was a Web Role for a Windows Azure Cloud Service.
Although the example project from Jon Canning's fork worked for me (although I did change the System.Web.Mvc assembly from 3.0.0.0 to 4.0.0.0, which required a bunch of editing in the web.config file to get the tests to run and pass), I got an error whenever I tried to run the same tests against an Azure ASP.NET MVC 4 Web Role project. The error was:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
The inner exception was:
System.InvalidOperationException: This method cannot be called during the application's pre-start initialization phase.
I started wondering how an Azure Web Role project based on ASP.NET MVC 4 was different to a normal ASP.NET MVC 4 project, and how such a difference would cause this error. I did a bit of searching on the web but didn't come across anybody trying to do the same thing that I was doing. Soon enough I managed to realise that it was to do with the Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener. Part of the role of this class seems to be to ensure that the web role is running in a hosted service or the Development Fabric (you'll see a message to this effect if you switch the startup project from the cloud service project to the web role project inside a cloud service solution, and then try to debug).
The solution? I removed the corresponding listener from the Web.config file of my Web Role project:
<configuration>
...
<system.diagnostics>
<trace>
<listeners>
<!--Remove this next 'add' element-->
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics"> <filter type="" /> </add>
</listeners>
</trace>
</system.diagnostics>
...
</configuration>
I was then able to run integration tests as normal against my Web Role project. I did, however, add the listener to the Web.Debug.config and Web.Release.config transformation files so that everything was still the same for normal deploying and debugging.
Maybe that will help somebody looking to use the MvcIntegrationTestFramework for Azure development.
EDIT I just realised that this solution might be a bit of a 'hack' because it might not let you do integration testing on application code that relates to Azure components (e.g. the special Azure caching mechanisms perhaps). That said, I haven't come across any issues to do with this yet, although I also haven't really written that many integration tests yet either...
Upvotes: 1
Reputation: 2970
I used Jon Canning's updated version (https://github.com/JonCanning/MvcIntegrationTestFramework/) and it solved my problem very well for controller methods that only accept value types and strings, but did not work for those that accepted classes.
It turns out there was an issue with the code for the updated MvcIntegrationTestFramework
.
I figured out how to fix it, but don't know where else to post the solution, so here it is:
A simple sample to show how it works is:
[TestMethod]
public void Account_LogOn_Post_Succeeds()
{
string loginUrl = "/Account/LogOn";
appHost.Start(browsingSession =>
{
var formData = new RouteValueDictionary
{
{ "UserName", "myusername" },
{ "Password", "mypassword" },
{ "RememberMe", "true"},
{ "returnUrl", "/myreturnurl"},
};
RequestResult loginResult = browsingSession.Post(loginUrl, formData);
// Add your test assertions here.
});
}
The call to browsingSession.Post
would ultimately cause the NameValueCollectionConversions.ConvertFromRouteValueDictionary(object anonymous)
method to be called, and the code for that was:
public static class NameValueCollectionConversions
{
public static NameValueCollection ConvertFromObject(object anonymous)
{
var nvc = new NameValueCollection();
var dict = new RouteValueDictionary(anonymous); // ** Problem 1
foreach (var kvp in dict)
{
if (kvp.Value == null)
{
throw new NullReferenceException(kvp.Key);
}
if (kvp.Value.GetType().Name.Contains("Anonymous"))
{
var prefix = kvp.Key + ".";
foreach (var innerkvp in new RouteValueDictionary(kvp.Value))
{
nvc.Add(prefix + innerkvp.Key, innerkvp.Value.ToString());
}
}
else
{
nvc.Add(kvp.Key, kvp.Value.ToString()); // ** Problem2
}
}
return nvc;
}
Then there was two problems:
new RouteValueDictionary(anonymous)
would cause the "new" RouteValueDictionary
to be created, but instead of 4 keys, there are only three, one of which was an array of 4 items.nvc.Add(kvp.Key, kvp.Value.ToString()
, the kvp.Value
is an array, and the ToString() gives:
"System.Collections.Generic.Dictionary'2+ValueCollection[System.String,System.Object]"
The fix (to my specific issue) was to change the code as follows:
var dict = anonymous as RouteValueDictionary; // creates it properly
if (null == dict)
{
dict = new RouteValueDictionary(anonymous);
}
After I made this change, then my model class would properly bind, and all would be well.
Upvotes: 0
Reputation: 1642
Have a look at my fork:
https://github.com/JonCanning/MvcIntegrationTestFramework/
Upvotes: 9
Reputation: 2063
I realize this is not the answer you're looking for but Selenium or Watin may be of use to you as an alternative to the Integration Test Framework.
Selenium will let you record tests as nUnit code so you can integrate with your existing test projects etc. Then your test can validate the DOM similarly to the Integration Test Framework. The advantage is Selenium tests can be executed with various different browsers.
Key caveat is that Selenium needs your app to be deployed on a web server, not sure if that's a show stopper for you.
Upvotes: 4