集成无UI自动化的痛苦测试的MVC应用程序 [英] Integration testing an MVC application without the pain of UI automation

查看:112
本文介绍了集成无UI自动化的痛苦测试的MVC应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始对将使用TDD在很大程度上写了一个新的MVC应用程序的开发。我想补充一些集成测试,以确保完全有线的应用程序(我使用StructureMap国际奥委会为,NHibernate的持久性)按预期工作。

虽然我打算写硒几个功能冒烟测试,维护的原因,我宁愿做我最集成测试通过直接调用使用好老的C#我的控制器的动作。

有是怎么一会做到这一点少得惊人的指导,所以我花了刺攻击计划


  1. 把所有的引导code OUT的Global.asax,并成为一个单独的类

  2. 试图利用MvcContrib-TestHelper或类似的创建ASP.NET依赖(上下文,请求等)

我已经完成第1步,但真的不知道如何继续执行步骤2.任何指导,将AP preciated。

 公共类引导程序
{
    公共静态无效的引导()
    {
        DependencyResolverInitializer.Initialize();
        FilterConfig.RegisterFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ModelBinders.Binders.DefaultBinder =新SharpModelBinder();
    }
}公共类DependencyResolverInitializer
{
    公共静态初始化集装箱()
    {
        VAR集装箱=​​新容器();
        container.Configure(X => x.Scan(Y =>
        {
            y.Assembly(typeof运算(Webmin.UI.FilterConfig).Assembly);
            y.WithDefaultConventions();
            y.LookForRegistries();        }));        DependencyResolver.SetResolver(新StructureMapDependencyResolver(容器));
        返回容器中;
    }
}公共类StructureMapDependencyResolver:的IDependencyResolver
{
    私人只读的IContainer _container;    公共StructureMapDependencyResolver(集装箱的IContainer)
    {
        _container =容器;
    }    公共对象GetService的(类型的serviceType)
    {
        如果(serviceType.IsAbstract || serviceType.IsInterface){
            返回_container.TryGetInstance(的serviceType);
        }
        返回_container.GetInstance(的serviceType);
    }    公共IEnumerable的<对象> GetServices(类型的serviceType)
    {
        返回_container.GetAllInstances(的serviceType).Cast<对象>();
    }
}


解决方案

如果你想要做自动化的终端到终端的测试,而无需通过用户界面将ASP.NET MVC应用程序的的一好办法做到这一点是编程之后发送HTTP请求到不同的URL并断言该系统的状态。

您的集成测试将基本上是这样的:


  1. 安排:开始Web服务器测试来承载Web应用程序

  2. 法:发送HTTP请求到特定的URL,这将是一个控制器动作来处理

  3. 断言:验证系统的状态(例如查找特定的数据库记录),或验证响应的内容(例如,寻找在返回的HTML特定字符串)

您可以轻松地将的过程中的的Web服务器使用的 CassiniDev 。此外,为了编程发送HTTP请求一个方便的方式是使用微软的ASP。 NET的Web API客户端库的。

下面是一个例子:

  [的TestFixture]
公共类When_retrieving_a_customer
{
    私人CassiniDevServer服务器;
    私人HttpClient的客户端;    [建立]
    公共无效的init()
    {
        //安排
        服务器=新CassiniDevServer();
        server.StartServer(.. \\相对\\路径\\为\\ web应用,80/,本地主机);
        客户端=新的HttpClient {BaseAddress =HTTP:// localhost的};
    }    [拆除]
    公共无效清除()
    {
        server.StopServer();
        server.Dispose();
    }    [测试]
    公共无效Should_return_a_view_containing_the_specified_customer_id()
    {
        //法案
        VAR响应= client.GetAsync(客户/ 123)结果。        //断言
        Assert.Contains(123,response.Content.ReadAsStringAsync()的结果。);
    }
}

如果你正在寻找这种技术的行动更完整的示例,您可以在品尝MVC找到它我的,我在那里证明它写的 =htt​​ps://github.com/ecampidoglio/gameoflife/tree/master/Src/AcceptanceTests/Steps相对=nofollow >自动化验收测试的。

I'm starting development on a new MVC application that will be largely written using TDD. I'd like to add some integration tests to ensure that the fully wired application (I'm using StructureMap for IOC, NHibernate for persistence) works as expected.

While I intend to write a few functional smoke tests with Selenium, for maintainability reasons, I'd rather do my most of integration testing by directly calling actions on my controllers using good old C#.

There is surprisingly little guidance on how one would accomplish this, so I took a stab on a plan of attack

  1. Pull all bootstrapping code out of Global.asax and into a separate class
  2. Attempt to leverage MvcContrib-TestHelper or similar to create ASP.NET dependencies (Context, Request, etc)

I've accomplished step 1, but really have no idea how to proceed to step 2. Any guidance would be appreciated.

public class Bootstrapper
{              
    public static void Bootstrap()
    {
        DependencyResolverInitializer.Initialize();
        FilterConfig.RegisterFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        ModelBinders.Binders.DefaultBinder = new SharpModelBinder();
    }           
}

public class DependencyResolverInitializer
{
    public static Container Initialize()
    {
        var container = new Container();
        container.Configure(x => x.Scan(y =>
        {
            y.Assembly(typeof(Webmin.UI.FilterConfig).Assembly);
            y.WithDefaultConventions();
            y.LookForRegistries();

        }));

        DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
        return container;
    }
}

public class StructureMapDependencyResolver : IDependencyResolver
{
    private readonly IContainer _container;

    public StructureMapDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        if (serviceType.IsAbstract || serviceType.IsInterface) {
            return _container.TryGetInstance(serviceType);
        }
        return _container.GetInstance(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _container.GetAllInstances(serviceType).Cast<object>();
    }
}

解决方案

If you want to do automated end-to-end testing of an ASP.NET MVC application without going through the UI, one good way to do it is to programmatically send HTTP requests to the different URLs and assert the state of the system afterwards.

Your integration tests would basically look like this:

  1. Arrange: Start a web server to host the web application under test
  2. Act: Send an HTTP request to a specific URL, which will be handled by a controller action
  3. Assert: Verify the state of the system (e.g. look for specific database records), or verify the contents of the response (e.g. look for specific strings in the returned HTML)

You can easily host an ASP.NET web app in an in-process web server using CassiniDev. Also, one convenient way to send HTTP requests programmatically is to use the Microsoft ASP.NET Web API Client Libraries.

Here's an example:

[TestFixture]
public class When_retrieving_a_customer
{
    private CassiniDevServer server;
    private HttpClient client;

    [SetUp]        
    public void Init()
    {
        // Arrange
        server = new CassiniDevServer();
        server.StartServer("..\relative\path\to\webapp", 80, "/", "localhost");
        client = new HttpClient { BaseAddress = "http://localhost" };
    }

    [TearDown]
    public void Cleanup()
    {
        server.StopServer();
        server.Dispose();
    }

    [Test]
    public void Should_return_a_view_containing_the_specified_customer_id()
    {
        // Act
        var response = client.GetAsync("customers/123").Result;

        // Assert
        Assert.Contains("123", response.Content.ReadAsStringAsync().Result);
    }
}

If you're looking for a more complete example of this technique in action, you can find it in a sample MVC 4 web application of mine, where I demonstrated it in the context of writing automated acceptance tests.

这篇关于集成无UI自动化的痛苦测试的MVC应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆