65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Canopy 对 Web 应用程序进行端到端测试

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (10投票s)

2018年5月14日

CPOL

2分钟阅读

viewsIcon

11737

本文将向您介绍 Canopy - 基于 Selenium 的端到端测试框架,它使用 F#。

为什么选择 Canopy

构建在 Selenium 之上的稳定层

Canopy 最关键的概念之一是可靠性 - 在执行操作时,框架会在 elementTimeoutcompareTimeoutpageTimeout 指定的时间范围内尝试,然后再失败,从而改善编写测试的体验。

表达力

语法看起来相当易于理解。

"Bio should contain twitter link" &&& fun _ ->
    url "https://github.com/Wkalmar"
    ".user-profile-bio" == "https://twitter.com/BohdanStupak1"

F#

在之前的文章中,我已经表达了对 F# 的强大和表达能力的看法。

编写更多测试

要开始,只需创建一个控制台应用程序,安装 Canopy NuGet 包,并在 Program.fs 中创建测试,如下所示

open canopy.configuration
open canopy.runner.classic
open System
open canopy.classic

//set path for chrome direver explicitly
chromeDir <- "C:\\"
start chrome

"Left bottom repostitory should be stationwalk.server" &&& fun _ ->
    //visit the following url
    url "https://github.com/Wkalmar"
    //get 4th child of the following selector
    let repo = nth 4 ".pinned-repo-item"
    //get element with the following selector inside repo element
    let firstRepoCaption = repo |> someElementWithin ".js-repo"
    match firstRepoCaption with    
    | Some caption -> read caption == "stationwalk.server" //if found read element caption 
                                                           //and compare it
    | None _ -> failwith "Element not found" //if none element found throw an exception

"Left bottom repostitory should be stationwalk.client" &&& fun _ ->
    url "https://github.com/Wkalmar"
    let repo = nth 5 ".pinned-repo-item"
    let firstRepoCaption = repo |> someElementWithin ".js-repo"
    match firstRepoCaption with
    | Some caption -> read caption == "stationwalk.client"
    | None _ -> failwith "Element not found"

"Bio should contain twitter link" &&& fun _ ->
    url "https://github.com/Wkalmar"
    ".user-profile-bio" == "https://twitter.com/BohdanStupak1"

run()

printfn "Press any key to exit..."
Console.ReadKey() |> ignore

quit()

访问 IWebDriver

如果您曾经使用 C# 编写过 Selenium 测试,您可能熟悉 IWebDriver 接口,您仍然可以使用它来进行一些高级配置。例如,假设我们希望以全屏模式运行测试。那么我们可以将以下函数添加到我们的 Program.fs 文件中

let maximizeBrowser (browser : IWebDriver) =    
  browser.Manage().Window.Maximize()

访问 IWebElement

Canopy 的大多数断言,例如 ==,都将 string(可以是 CSS 或 XPath 选择器)或 IWebElement 类型的实例作为参数,如果您曾经使用 C# 编写过 Selenium 测试,那么您可能已经熟悉 IWebElement 类型。因此,假设我们想要将某些内容上传到文件上传控件。

let uploadFile fullFilePath =
  (element "input[type='file']").SendKeys(fullFilePath)

拆分大文件

我实践过的保持测试项目可维护性的模式是将选择器提取到页面模块中,并将测试移动到单独的文件中。

让我们重新审视我们的 GitHub 示例,将选择器移动到单独的模块中

module GithubProfilePage

let pinnedRepository = ".pinned-repo-item"
let bio = ".user-profile-bio"

现在我们可以在测试中引用它们,我们也将测试移动到单独的模块中

module GithubProfileTests

open canopy.runner.classic
open canopy.classic

let all() =
    context "Github page tests"

    "Left bottom repostitory should be staionwalk.server" &&& fun _ ->
        url "https://github.com/Wkalmar"
        let repo = nth 4 GithubProfilePage.pinnedRepository
        let firstRepoCaption = repo |> someElementWithin ".js-repo"
        match firstRepoCaption with
        | Some caption -> read caption == "stationwalk.server"
        | None _ -> failwith "Element not found"

    "Right bottom repostitory should be staionwalk.client" &&& fun _ ->
        url "https://github.com/Wkalmar"
        let repo = nth 5 GithubProfilePage.pinnedRepository
        let firstRepoCaption = repo |> someElementWithin ".js-repo"
        match firstRepoCaption with
        | Some caption -> read caption == "stationwalk.client"
        | None _ -> failwith "Element not found"

    "Bio should contain twitter link" &&& fun _ ->
        url "https://github.com/Wkalmar"
        GithubProfilePage.bio == "https://twitter.com/BohdanStupak1"

我们的 Program.fs 将如下所示

open canopy.configuration
open canopy.runner.classic
open System
open canopy.classic

chromeDir <- "C:\\"
start chrome

GithubProfileTests.all()

run()

printfn "Press any key to exit..."
Console.ReadKey() |> ignore

quit()

并行运行测试

最近,Canopy 从 1.x 升级到 2.x,其中一项很棒的新功能是能够并行运行测试。

让我们通过使用此功能重新审视我们的示例

module GithubProfileTests

open canopy.parallell.functions
open canopy.types
open prunner

let all() =  
    "Left bottom repostitory should be stationwalk.server" &&& fun _ ->
        let browser = start Chrome        
        url "https://github.com/Wkalmar" browser
        let repo = nth 4 GithubProfilePage.pinnedRepository browser
        let firstRepoCaption = someElementWithin ".js-repo" repo browser
        match firstRepoCaption with
        | Some caption -> equals (read caption browser) "stationwalk.server" browser
        | None _ -> failwith "Element not found"

    "Right bottom repostitory should be stationwalk.client" &&& fun _ ->
        let browser = start Chrome        
        url "https://github.com/Wkalmar" browser
        let repo = nth 5 GithubProfilePage.pinnedRepository browser
        let firstRepoCaption = someElementWithin ".js-repo" repo browser
        match firstRepoCaption with
        | Some caption -> equals (read caption browser) "stationwalk.client" browser
        | None _ -> failwith "Element not found"

    "Bio should contain twitter link" &&& fun _ ->
        let browser = start Chrome        
        url "https://github.com/Wkalmar" browser
        equals GithubProfilePage.bio "https://twitter.com/BohdanStupak1" browser

这里的关键技巧是,每个测试现在都使用其自己浏览器副本,并且断言现在来自开放的 canopy.parallel.functions,它接受 browser 作为参数。另外,请注意 prunner 依赖项,您可以从 这里 获取。

无头测试

在无头浏览器中进行测试似乎是现在的新潮流。虽然我对此并不认同,但我仍然可以向您保证,Canopy 支持在无头浏览器中进行测试。您可以按如下方式在无头 Chrome 中运行测试

let browser = start ChromeHeadless

结论

我希望本文能说服您,Canopy 是一个强大且易于使用的框架,可用于构建应用程序的端到端测试层。

© . All rights reserved.