我正在编写代码来测试C#MVC3应用程序。我可以测试控制器但是如何测试视图中的代码?这包括javascript和剃刀风格的代码。
是否有可用的工具可以在C#中模拟视图或测试视图和javascript?
答案 0 :(得分:2)
以下是关于测试视图的渲染输出。例如,可以将此文本输出加载到DOM中,以便使用XPath进行进一步分析(对于XHTML使用XmlReader
或对于SGML样式的HTML使用HtmlAgilityPack
)。通过一些不错的帮助方法,可以轻松检查视图的特定部分,例如测试//a[@href='#']
或您要测试的任何其他内容。这有助于使单元测试更稳定。
当使用Razor而不是“爆炸式”WebForms引擎时,人们会发现这很容易,但由于Razor视图引擎的许多内部工作原理和使用部件的视图({},因此结果恰恰相反。特别是{1}} HTTP请求生命周期。实际上,正确测试生成的输出需要大量运行代码才能获得可靠和适当的结果,如果你在混合中使用诸如可移植区域(来自MVCContrib项目)之类的奇特东西,则更是如此。
操作和URL的HTML帮助程序要求正确初始化路由,正确设置路由字典,控制器也必须存在,并且还有与加载视图数据相关的其他“陷阱”,例如设置查看数据字典......
我们最终创建了一个HtmlHelper
类,它实际上将在您要测试的Web物理路径上实例化一个应用程序主机(可以静态缓存,每次单个测试的重新初始化是不切实际的,因为初始化滞后):
ViewRenderer
host = (ApplicationHost)System.Web.Hosting.ApplicationHost.CreateApplicationHost(typeof(ApplicationHost), "/", physicalDir.FullName);
类继承自ApplicationHost
,因为主机将加载到单独的应用程序域中。主机执行各种不正常的初始化操作,以便正确初始化MarshalByRefObject
(注册路由等的HttpApplication
中的代码),同时禁用某些方面(例如身份验证和授权)。 警告,严重的黑客攻击。使用风险由您自己承担。
global.asax.cs
public ApplicationHost() {
ApplicationMode.UnitTesting = true; // set a flag on a global helper class to indicate what mode we're running in; this flag can be evaluated in the global.asax.cs code to skip code which shall not run when unit testing
// first we need to tweak the configuration to successfully perform requests and initialization later
AuthenticationSection authenticationSection = (AuthenticationSection)WebConfigurationManager.GetSection("system.web/authentication");
ClearReadOnly(authenticationSection);
authenticationSection.Mode = AuthenticationMode.None;
AuthorizationSection authorizationSection = (AuthorizationSection)WebConfigurationManager.GetSection("system.web/authorization");
ClearReadOnly(authorizationSection);
AuthorizationRuleCollection authorizationRules = authorizationSection.Rules;
ClearReadOnly(authorizationRules);
authorizationRules.Clear();
AuthorizationRule rule = new AuthorizationRule(AuthorizationRuleAction.Allow);
rule.Users.Add("*");
authorizationRules.Add(rule);
// now we execute a bogus request to fully initialize the application
ApplicationCatcher catcher = new ApplicationCatcher();
HttpRuntime.ProcessRequest(new SimpleWorkerRequest("/404.axd", "", catcher));
if (catcher.ApplicationInstance == null) {
throw new InvalidOperationException("Initialization failed, could not get application type");
}
applicationType = catcher.ApplicationInstance.GetType().BaseType;
}
方法使用反射来使内存中的Web配置变得可变:
ClearReadOnly
private static void ClearReadOnly(ConfigurationElement element) {
for (Type type = element.GetType(); type != null; type = type.BaseType) {
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.DeclaredOnly).Where(f => typeof(bool).IsAssignableFrom(f.FieldType) && f.Name.EndsWith("ReadOnly", StringComparison.OrdinalIgnoreCase))) {
field.SetValue(element, false);
}
}
}
是存储应用程序实例的“null”ApplicationCatcher
。我找不到另一种方法来初始化应用程序实例并获得它。它的核心非常简单。
TextWriter
现在,我们可以渲染几乎所有(Razor)视图,就像它被托管在真实的Web服务器中一样,创建几乎完整的HTTP生命周期来呈现它:
public override void Close() {
Flush();
}
public override void Flush() {
if ((applicationInstance == null) && (HttpContext.Current != null)) {
applicationInstance = HttpContext.Current.ApplicationInstance;
}
}
也许这可以帮助您获得一些结果。一般来说,很多人都说测试视图的麻烦并不值得。我会让你成为法官。
答案 1 :(得分:1)
查看vantheshark的文章,它介绍了如何使用NSubstitute模拟ASP.NET MVC View引擎。