Spiga

使用WatiN对ASP.NET页面进行单元测试

2008-03-30 14:47 by Anders Cui, 6335 visits, 收藏, 编辑

本文翻译自:Unit Testing ASP.NET Pages Using WatiN

引言

单元测试是应用程序设计的一个重要部分,它可应用于程序的多个层次。本文将主要关注用户界面层的单元测试。我们将使用WatiN 测试ASP.NET应用程序。

什么是WatiN?

WatiN 是一个源自Watir的工具,用于测试Web页面。WatiN表示Web Application Testing in .NET。

我们要测试什么?

在本文中我们将测试一个简单的ASP.NET页面,用这个页面来演示认同、接受(agreement acceptance)的场景。用户在文本框中输入名字,点击“I agree”复选框,然后按下submit按钮。这显然是一个非常简单的页面,在你熟悉了WatiN框架的工作机制后,就可以将这里的理念用于大型页面的测试了。

这里是待测页面的截图:

WatiNImage1

测试认同(Agreement)页面:

向解决方案添加一个类库项目,并为其添加对测试工具(我这里用的是MbUnit,但你完全可以使用NUnit或VSTS的测试项目)和WatiN库的引用。你可以在这里下载WatiN。

下面的测试代码用来确保用户已经认同。

[TestFixture(ApartmentState = ApartmentState.STA)]
public class TestAgreementPage
{
    [Test]
    public void TestCanAcceptUserAgreement()
    {
        IE ie = new IE(ConfigurationManager.AppSettings["DefaultPageUrl"]);
        ie.TextField("txtName").TypeText("Mohammad Azam");
        ie.CheckBox("chkAgree").Checked = true;
        ie.Button("btnAgree").Click();
 
        Assert.AreEqual("Valid", ie.Span("lblMessage").Text);
    }
}

这个类有TestFixture特性(Attribute),STA值确保该测试运行于STA(Single Threaded Apartment)状态下。这是因为测试代码要加载IE。

WatiN中的IE类完成了主要工作。IE类打开IE,通过name或id来引用html控件。这一行ie.TextField("txtName").TypeText("Mohammad Azam"),引用了id为“txtName”的文本框。浏览器加载后,WatiN会将值“Mohammad Azam”写入id为“txtName”的文本框。这个过程在测试时你会看到的。然后id为“chkAgree”的复选框会被选中。最后,WatiN会按下提交按钮,窗体被提交。

运行测试,失败。因为名为“lblMessage”的Label从未被赋值为“Valid”。加上这段代码:

protected void btnAgree_Click(object sender, EventArgs e)
{
    lblMessage.Text = "Valid";
}

现在,如果你运行测试它会通过。但是,好像不太正确。如果我们把这一行测试代码删掉:

ie.CheckBox("chkAgree").Checked = true;

再次运行测试,依然能通过。这可不对!应当只有在CheckBox选中时才可通过。将页面的Code behind代码改一下。

protected void btnAgree_Click(object sender, EventArgs e)
{
    if (chkAgree.Checked)
    {
        lblMessage.Text = "Valid";
    }
}

现在,测试只有在CheckBox选中时才可通过了。

以编程方式运行Web服务器:

在上例中我们需要运行WebServer,要么是通过命令行工具,要么是通过运行Web项目。但有时我们需要单元测试项目能够动态打开一个WebServer。一起来看看。

首先,如果你需要打开ASP.NET内部服务器(WebDev.WebServer),可以使用命令行。语法如下:

WebDev.WebServer.exe /port:1950 /path:"C:\Projects\MyWebApplication"

需要定位到WebDev.WebServer所在的目录,默认情况下它在:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe

好了,现在来看看如何在单元测试中打开服务器。首先,添加必要的配置(App.config中)。

<configuration>
    <appSettings>
        <add key="WebServerExePath" value="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe"/>
        <add key="Port" value="4463"/>
        <add key="WebApplicationPath" value="c:\projects\demowatiN\demowatiN" />
        <add key="DefaultPageUrl" value="http://localhost:4463/Default.aspx" />
    </appSettings>
</configuration>

BaseTestPage类可以通过这些信息运行服务器,所有继承了它的测试类都可以使用这个功能了。

下面是BaseTestPage类的完整代码:

public class BaseTestPage
{
    static Process server = null;
 
    static BaseTestPage()
    {
        if (Process.GetProcessesByName("WebDev.WebServer").Length == 0)
        {
            string webServerExePath = (string)ConfigurationManager.AppSettings["WebServerExePath"];
            server = new Process();
            Process.Start(webServerExePath, GetWebServerArguments());
        }
    }
 
    public static string GetWebServerArguments()
    {
        string args = String.Format("/port:{0} /path:\"{1}\"", GetPort(), GetWebApplicationPath());
        if (String.IsNullOrEmpty(args)) throw new ArgumentNullException("Arguments is not defined");
        return args;
    }
 
    public static string GetPort()
    {
        string port = ConfigurationManager.AppSettings["Port"] as String;
        if (String.IsNullOrEmpty(port)) throw new ArgumentNullException("Port is null or empty");
 
        return port;
    }
 
    public static string GetWebApplicationPath()
    {
        string webApplicationPath = ConfigurationManager.AppSettings["WebApplicationPath"] as String;
        if (String.IsNullOrEmpty(webApplicationPath)) throw new ArgumentNullException("WebApplicationPath is null or empty");
 
        return webApplicationPath;
    }
}

如果服务器没有运行,我们会新建一个进程运行它,否则就使用已有的进程。GetWebServerArguments()、GetPort()和GetWebApplicationPath()仅仅是辅助方法,可以提高可读性。

最后,你可以让单元测试类继承该类:

public class TestAgreementPage : BaseTestPage

现在,运行单元测试项目时,它会运行WebServer,然后再执行所有测试。

结论:

在本文中,我们学习了如何对用户界面层进行单元测试,这些测试可帮助我们理解UI的需求,并快速地看到基于用户输入所得到的结果。而如果手动进行测试,就要花费很多时间了。

源码:点击这里

作者:Anders Cui
出处:http://anderslly.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Add your comment

24 条回复

  1. #1楼 生鱼片      2008-03-30 17:44
    支持下
     回复 引用 查看   
  2. #2楼 王德水      2008-03-30 18:01
    支持,最近也在用watin
     回复 引用 查看   
  3. #3楼[楼主] Anders Cui      2008-03-30 18:37
    @生鱼片
    @王德水
    谢谢支持 :)
     回复 引用 查看   
  4. #4楼 Sam Lin      2008-03-30 19:40
    我稍微用一下WatiN觉得还不是很好用,或许不太会用
    1、对下拉框支持性不好
    2、对JavaScript事件不支持,比如说你点击一个文本框然后弹出日历控件
     回复 引用 查看   
  5. #5楼[楼主] Anders Cui      2008-03-30 21:23
    @Sam Lin
    嗯,我也用的不多
    再好好学学它的用法
     回复 引用 查看   
  6. #6楼 峻祁连      2008-03-30 21:28
    嗯,写得很好,支持
     回复 引用 查看   
  7. #7楼 任力      2008-03-30 22:16
    辛苦老兄了,呵呵。。我这不能下,明天去公司了,一定要试试
     回复 引用 查看   
  8. #8楼 HuangXB      2008-03-30 22:33
    支持,学习一下
     回复 引用 查看   
  9. #9楼 Anytao      2008-03-31 09:39
    翻译的不错,很受用:-)
     回复 引用 查看   
  10. #10楼[楼主] Anders Cui      2008-03-31 10:01
    @Anytao
    文笔要向你看齐 :D
     回复 引用 查看   
  11. #11楼 阿坝[未注册用户]2008-04-04 22:24
    此安装不支持该项目类型? 请赐教
     回复 引用   
  12. #12楼[楼主] Anders Cui      2008-04-05 16:27
    @阿坝
    示例代码我是在VS2005下的Web Application项目开发的
    不知是否跟这个有关系?
     回复 引用 查看   
  13. #13楼 阿坝[未注册用户]2008-04-05 17:46
    我的也是啊~~~
     回复 引用   
  14. #14楼 Frank Wang[未注册用户]2008-04-22 13:04
    非常感谢
     回复 引用   
  15. #15楼 hans.hu      2009-04-30 10:05
    看起来挺诱人的,要试试看。
     回复 引用 查看   
  16. #16楼 Flyear      2009-06-02 10:51
    using NUnit.Framework;
    using WatiN.Core;
    using System.Threading;
    namespace TestAgreement
    {
    [TestFixture(ApartmentState = ApartmentState.STA)]

    错误:“NUnit.Framework.TestFixtureAttribute”并不包含“ApartmentState”的定义

    不知道这是为什么啊?
     回复 引用 查看   
  17. #17楼 sa1[未注册用户]2009-08-07 17:41
    请问仅仅在有WebDev.WebServer.exe和它依赖的dll的情况下,没有安装vs的机器上能否启动网站?
     回复 引用   
  18. #18楼[楼主] Anders Cui      2009-08-07 21:26
    @sa1
    理论上是可以的,VS只是IDE啊
     回复 引用 查看   
  19. #19楼[楼主] Anders Cui      2009-08-07 23:01
    @Flyear
    这里用的是MbUnit
     回复 引用 查看   
  20. #20楼 Bazishan      2009-09-27 15:33
    写的不错,学习了!
     回复 引用 查看   
  21. #21楼 ma.lyn      2010-03-24 12:25
    MARK
     回复 引用 查看   
  22. #22楼 風語者·疾風      2011-02-24 17:49
    我只想说一句,这个不是单元测试,是自动化测试,也算是集成测试吧
     回复 引用 查看