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






4.61/5 (10投票s)
本文将向您介绍 Canopy - 基于 Selenium 的端到端测试框架,它使用 F#。
为什么选择 Canopy
构建在 Selenium 之上的稳定层
Canopy 最关键的概念之一是可靠性 - 在执行操作时,框架会在 elementTimeout
或 compareTimeout
或 pageTimeout
指定的时间范围内尝试,然后再失败,从而改善编写测试的体验。
表达力
语法看起来相当易于理解。
"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 是一个强大且易于使用的框架,可用于构建应用程序的端到端测试层。