[30 days quick start TDD] [Day 27] TDD actual practice part 1 & amp; ndash; ATDD first red light

[30 days to get started quickly TDD] [27 Day] TDD combat exercises part 1-ATDD first red light


Foreword

Until the previous article, each fragment TDD needed to have a brief introduction again, I am sure you readers are also very clear understanding, I want to focus on the expression, or a word: everything in order to meet users' needs.

Next, the author through a simple example, from the surface to introduce the practice of the order, how a user needs from the beginning to the end of a cycle (acceptance test cases may not be complete, but the cycle is the same)

Examples Introduction

Background of this example, an online banking system.

The side selected user story, a login function. Because most of the developers of the system have done, you should have a login function, even if not worked on, or at least used. We hope that through such examples, readers will better understand, have more resonance.

Of course, because this is not a real system, so fool-proof surface or the demand side may not be perfect, here we talk to readers say sorry.

Defining Requirements

PO:.. "Hey, our system should have a function when the user logged into the system, if the login page has not been authenticated, then funnel users to login first page after successful login, and then guide to our home. "

In accordance with the PO to say, after discussions with the PO, PO, testers and developers, decided to use a user story to describe such a demand:

"We need a login function:
an In the Order to verify identity, prevent illegal users using the system
As a online users
I want to verify the identity of the user is legitimate."

TDD development process as described in the previous article said, when we set up a user story, the next step is:

  1. According to the user story, the establishment of a BDD feature.
  2. Based on user story break down into several acceptance test cases.

Create a test project

First, create a test project, named "TestWebBank". As shown below:

1-create test project

In the test project, add a reference in a few need to use TDD through NuGet:

  1. SpecFlow (used to practice the BDD)
  2. Selenium.WebDriver (used to execute Selenium test scripts)
  3. RhinoMocks (Unit Testing for practice in the Stub Mock object)

And SpecFlow App.Config in the setting change performed using MSTest. As shown below:

2-adding reference in testing project

Login Feature establishment of archives

In the test project, add a Login.Feature file. As shown below:

3-adding login feature

The user story portion, the feature is filled in, as shown below:

4-editing feature

The confirmation screen

After determining the user story, then testers and developers, to discuss co-PO, which is how acceptance of the user story.

PO or users usually need to screen through the UI or prototype system, it is easier to confirm, this is not their child to function. Thus, through the whiteboard, pen and paper, Word, PowerPoint, build prototype / mockup tools (such as Balsamiq Mockups, Moqups, axure) to assist quickly confirm this picture, whether the user wishes some features.

The example here is developers quickly build a Web site project, and made only a look, but did not wear clothes html pages, with only two entries, namely:

  1. ATM card ID
  2. password

And an "OK" sign button.

.aspx program:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>




    


    
  
  
提款卡ID:
密码:

Screen as shown below:

5-login

(Developers / testers: Of course the picture is not so ugly, but basically the picture is not just to have these entries can be?)

After the confirmation screen is correct, the next to define sign-in, you should have the system behavior.

Build acceptance test cases

After discussion, the first definition of the sign-in should be to have the following several features:

  1. Login successful, lead to the system home page (index.aspx)
  2. 登入失败时,画面要呈现“验证失败,出现密码错误”的消息

在 user story card 背后,写上这两点验收测试案例之后,接下来我们先在 SpecFlow 的 feature 档中,将这两个 scenario 补上去。如下图所示:

6-adding scenario

笔者建议在描述 scenario 的时候,就应该要有拟真的 input/output 数据,这样才会比较贴近验收测试的情况。

而有了这样的 scenario/acceptance test cases ,也可以方便我们先行准备测试数据。

接着透过 SpecFlow 自动产生 step 的功能,帮我们产生 Login.feature 所对应的 step 文件内容。如下图所示:

7-generate step context

Step 的程序如下:

using System;
using TechTalk.SpecFlow;

namespace TestWebBank
{
    [Binding]
    public class 登入功能Steps
    {
        [Given(@"在登入页面")]
        public void Given在登入页面()
        {
            ScenarioContext.Current.Pending();
        }
        
        [Given(@"提款卡Id输入""(.*)""")]
        public void Given提款卡Id输入(int p0)
        {
            ScenarioContext.Current.Pending();
        }
        
        [Given(@"密码输入""(.*)""")]
        public void Given密码输入(int p0)
        {
            ScenarioContext.Current.Pending();
        }
        
        [When(@"按下确认按钮")]
        public void When按下确认按钮()
        {
            ScenarioContext.Current.Pending();
        }
        
        [Then(@"页面url为""(.*)""")]
        public void Then页面Url为(string p0)
        {
            ScenarioContext.Current.Pending();
        }
        
        [Then(@"呈现消息为""(.*)""")]
        public void Then呈现消息为(string p0)
        {
            ScenarioContext.Current.Pending();
        }
    }
}

到这边, user story, acceptance test cases, feature, scenario 都定义好了,我们也已经建立好测试项目与网站项目了。

接下来就要开始撰写验收测试程序了。

撰写验收测试程序 – Selenium

我们已经有了简单的网页,也有了期望的 scenario ,接下来测试人员就可以开始撰写自动化的验收测试程序了。

这边笔者建议,如果测试人员对 Selenium 的 library 还不够熟悉时,开发人员可以先给点帮助。例如先 hard-code 写出两种结果:

  1. 当按下“确认”按钮后,导到 index 页面的功能。
  2. 当按下“确认”按钮后,出现错误消息的功能。

Hard-code 程序如下:

    protected void btnLogin_Click(object sender, EventArgs e)
    {
        //密码验证错误
        //this.Message.Text = @"密码输入错误";

        //密码验证成功
        //Response.Redirect("index.aspx");
    }

让测试人员/开发人员,可以先自行透过 Selenium IDE 来录制 Selenium 脚本。

这边举“验证成功后,要导到 index.aspx ”为例。

  1. 透过 Firefox 浏览 Login 页面。
  2. 打开 Selenium IDE ,开始录制。
  3. 在提款卡 ID 中,输入 1234 。
  4. 在密码中,输入 91 。
  5. 按下确认按钮,导到 index.aspx 。

Selenium 录制脚本,如下图所示:

录制输入数据:

8-record selenium

导到 index 页面:

9-redirect to index

这边别忘了,我们还要验证“是否导到了 index.aspx ”,这里笔者先加上注解就好,因为最后是要透过 WebDriver 去做验证。最后将此 scenario 存成 loginSuccess ,当然最好的方式是,存成跟 scenario 可以直接对照的文件名。

10-save selenium test cases

依此类推,将密码输入错误,验证失败的脚本也录制好。如下图所示:

11-login failed

Export Selenium Test Cases to Selenium.WebDriver Code

如同前面文章: [30天快速上手TDD][Day 8]Integration Testing & Web UI Testing 所提到,我们将录好的 selenium test cases ,透过 export 转成 C# with NUnit 的 code 。如下图所示:

12-save to NUnit

程序如下所示:

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;

namespace SeleniumTests
{
    [TestFixture]
    public class LoginSuccess
    {
        private IWebDriver driver;
        private StringBuilder verificationErrors;
        private string baseURL;
        
        [SetUp]
        public void SetupTest()
        {
            driver = new FirefoxDriver();
            baseURL = "http://localhost:10542/";
            verificationErrors = new StringBuilder();
        }
        
        [TearDown]
        public void TeardownTest()
        {
            try
            {
                driver.Quit();
            }
            catch (Exception)
            {
                // Ignore errors if unable to close the browser
            }
            Assert.AreEqual("", verificationErrors.ToString());
        }
        
        [Test]
        public void TheLoginSuccessTest()
        {
            driver.Navigate().GoToUrl(baseURL + "/WebBankSite/Login.aspx");
            driver.FindElement(By.Id("txtCardId")).Clear();
            driver.FindElement(By.Id("txtCardId")).SendKeys("1234");
            driver.FindElement(By.Id("txtPassword")).Clear();
            driver.FindElement(By.Id("txtPassword")).SendKeys("91");
            driver.FindElement(By.Id("btnLogin")).Click();
            // 验证url是否为index.aspx
        }
        private bool IsElementPresent(By by)
        {
            try
            {
                driver.FindElement(by);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }
    }
}

有了这样的 Selenium 自动测试程序,了解每一行程序的内容之后,我们只需要依照我们所定义好 SpecFlow 的 Scenario ,在 Steps 中,把对应的动作,放进去每一个 scenario 的关键字 function 中即可。这边因为使用的是 MSTest ,因此一些语法也要做点小修改。

修改完成的 step 内容,程序如下所示:

using System;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using TechTalk.SpecFlow;

namespace TestWebBank
{
    [Binding]
    public class 登入功能Steps
    {
        #region Test Setting

        private static IWebDriver driver;
        private static StringBuilder verificationErrors;
        private static string baseURL;

        [BeforeFeature("WebBank")]
        public static void BeforeFeatureWebAtm()
        {
            driver = new FirefoxDriver();
            //请自行修改为网站的domain name与port
            baseURL = "http://localhost:10542";
            verificationErrors = new StringBuilder();
        }

        [AfterFeature("WebBank")]
        public static void AfterFeatureWebAtm()
        {
            try
            {
                driver.Quit();
            }
            catch (Exception)
            {
                // Ignore errors if unable to close the browser
            }
            Assert.AreEqual("", verificationErrors.ToString());
        }

        #endregion Test Setting

        [Given(@"在登入页面")]
        public void Given在登入页面()
        {
            driver.Navigate().GoToUrl(baseURL + "/WebBankSite/Login.aspx");
        }

        [Given(@"提款卡Id输入""(.*)""")]
        public void Given提款卡Id输入(string cardId)
        {
            driver.FindElement(By.Id("txtCardId")).Clear();
            driver.FindElement(By.Id("txtCardId")).SendKeys(cardId);
        }

        [Given(@"密码输入""(.*)""")]
        public void Given密码输入(string password)
        {
            driver.FindElement(By.Id("txtPassword")).Clear();
            driver.FindElement(By.Id("txtPassword")).SendKeys(password);
        }

        [When(@"按下确认按钮")]
        public void When按下确认按钮()
        {
            driver.FindElement(By.Id("btnLogin")).Click();
        }

        [Then(@"页面url为""(.*)""")]
        public void Then页面Url为(string url)
        {
            var expected = string.Format("{0}/WebBankSite/{1}", baseURL, url);
            Assert.AreEqual(expected, driver.Url);
        }

        [Then(@"呈现消息为""(.*)""")]
        public void Then呈现消息为(string message)
        {
            Assert.AreEqual(message, driver.FindElement(By.Id("Message")).Text);
        }
    }
}

执行 Scenario 的测试

既然测试的程序都写完了,让我们来执行一下测试,看一下测试的结果。

13-selenium test failed

执行 Selenium WebDriver 的测试时间可能会比较久一点点,因为要透过 WebDriver 启动 Firefox ,并且执行相关 Selenium test cases 。若读者需要测试其他浏览器,只要参考对应 browser 的 WebDriver 即可。

可以看到两个测试都失败了,错误消息分别为:

  1. LoginSuccess: Assert.AreEqual 失败。预期: 。实际: http://localhost:10542/WebBankSite/Login.aspx
  2. LoginFailed: Assert.AreEqual 失败。预期: <密码输入错误> 。实际: <>

红灯!这就是整个 ATDD 的第一个阶段:红灯

小结

为了避免篇幅太长,这篇文章到这边,就只先介绍了:

  1. 如何从 PO 的描述中,定义出 user story 与 acceptance test cases 。
  2. 如何建立 BDD 相关的 feature 与 scenario 。
  3. 如何透过 Selenium 来设计验收测试程序。
  4. 如何结合 BDD 的 steps 与 Selenium.WebDriver 。

下一篇文章,就比较单纯一点了,我们只要想办法让红灯变成绿灯即可。


或许您会对下列培训课程感兴趣:

  1. 2019/7/27(六)~2019/7/28(日):演化式设计:测试驱动开发与持续重构 第六梯次(中国台北)
  2. 2019/8/16(五)~2019/8/18(日):【C#进阶设计-从重构学会高易用性与高弹性API设计】第二梯次(中国台北)
  3. 2019/9/21(六)~2019/9/22(日):Clean Coder:DI 与 AOP 进阶实战 第二梯次(中国台北)
  4. 2019/10/19(六):【针对遗留代码加入单元测试的艺术】第七梯次(中国台北)
  5. 2019/10/20(日):【极速开发】第八梯次(中国台北)

想收到第一手公开培训课程资讯,或想询问企业内训、顾问、教练、咨询服务的,请洽 Facebook 粉丝专页:91敏捷开发之路。

Original: Large column  [30 days to get started quickly TDD] [Day 27] TDD combat exercises part 1 & ndash; ATDD first red light


Guess you like

Origin www.cnblogs.com/chinatrump/p/11468279.html
TDD