Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,44 @@ linkTitle: "设计策略"
weight: 1
---

{{% pageinfo color="warning" %}}
<p class="lead">
<i class="fas fa-language d-4"></i>
Most of the documentation found in this section is still in English.
Please note we are not accepting pull requests to translate this content
as translating documentation of legacy components does not add value to
the community nor the project.
</p>
{{% /pageinfo %}}

(previously located: https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests)

## Overview
Over time, projects tend to accumulate large numbers of tests. As the total number of tests increases,
it becomes harder to make changes to the codebase --- a single "simple" change may
cause numerous tests to fail, even though the application still works properly.
Sometimes these problems are unavoidable, but when they do occur you want to be
up and running again as quickly as possible. The following design patterns and
strategies have been used before with WebDriver to help to make tests easier to write and maintain. They may help you too.

[DomainDrivenDesign]({{< ref "encouraged/domain_specific_language.md" >}}): Express your tests in the language of the end-user of the app.
[PageObjects]({{< ref "encouraged/page_object_models.md" >}}): A simple abstraction of the UI of your web app.
LoadableComponent: Modeling PageObjects as components.
BotStyleTests: Using a command-based approach to automating tests, rather than the object-based approach that PageObjects encourage

## Loadable Component

### What Is It?

The LoadableComponent is a base class that aims to make writing PageObjects
less painful. It does this by providing a standard way of ensuring that pages
are loaded and providing hooks to make debugging the failure of a page to load
easier. You can use it to help reduce the amount of boilerplate code in your
tests, which in turn make maintaining your tests less tiresome.

There is currently an implementation in Java that ships as part of Selenium 2,
but the approach used is simple enough to be implemented in any language.

### Simple Usage

As an example of a UI that we'd like to model, take a look at
the [new issue](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=I-defect%2Cneeds-triaging&projects=&template=bug-report.yml&title=%5B%F0%9F%90%9B+Bug%5D%3A+) page.
From the point of view of a test author, this offers the service of being
able to file a new issue. A basic Page Object would look like:

(原位置: https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests)

## 概览

随着时间推移, 项目往往会积累大量测试.
随着测试总数的增加, 对代码库进行改动会变得更困难 —— 即便只是一次“简单”的改动,
也可能导致大量测试失败, 而应用本身仍然能正常工作.
有时这种问题不可避免, 但一旦发生, 你希望能尽快恢复运行.
下面介绍的一些设计模式与策略在 WebDriver 场景下被证明可以简化测试编写与维护,
可能也对你有帮助.

[领域驱动设计]({{< ref "encouraged/domain_specific_language.md" >}}): 以最终用户的语言来表达测试.

[页面对象]({{< ref "encouraged/page_object_models.md" >}}): 对 Web 应用 UI 的一种简单抽象.

LoadableComponent: 把页面对象建模为可加载的组件.

BotStyleTests: 使用以命令为导向的自动化测试方式, 而不是页面对象更偏向的对象化方法
Comment on lines +24 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Improve translation consistency for technical terms

Suggested change
BotStyleTests: 使用以命令为导向的自动化测试方式, 而不是页面对象更偏向的对象化方法
BotStyleTests: 使用以命令为导向的自动化测试方式, 而不是页面对象更偏向的基于对象的方法



## Loadable Component

### 其是什么?

LoadableComponent 是一个基类, 目标是让编写页面对象更轻松.
它通过提供一套标准机制来确保页面被正确加载, 并提供在页面加载失败时用于调试的钩子.
你可以利用它来减少测试中的样板代码, 从而降低维护测试的工作量.

目前在 Selenium 中包含了一个 Java 实现,
但该方法足够简单, 可在任何语言中实现.

### 简单用法

举个我们想要建模的 UI 的例子, 看看 [new issue](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=I-defect%2Cneeds-triaging&projects=&template=bug-report.yml&title=%5B%F0%9F%90%9B+Bug%5D%3A+) 页面.
对于测试作者而言, 该页面的作用是提供一个提交新 issue 的功能.
一个基本的页面对象看起来像:


```java
package com.example.webdriver;
Expand Down Expand Up @@ -121,18 +115,20 @@ public class EditIssue {
}
```

In order to turn this into a LoadableComponent, all we need to do is to set that as the base type:
为了把它变成一个 LoadableComponent,
我们所要做的就是将其设为基类:

```java
public class EditIssue extends LoadableComponent<EditIssue> {
// rest of class ignored for now
}
```

This signature looks a little unusual, but it all means is that
this class represents a LoadableComponent that loads the EditIssue page.
这个签名看起来有些不寻常, 但它的含义很简单:
该类表示一个用于加载 EditIssue 页面 的 LoadableComponent.

By extending this base class, we need to implement two new methods:

通过继承这个基类, 我们需要实现两个新方法:

```java
@Override
Expand All @@ -147,15 +143,16 @@ By extending this base class, we need to implement two new methods:
}
```

The `load` method is used to navigate to the page, whilst the `isLoaded` method
is used to determine whether we are on the right page. Although the
method looks like it should return a boolean, instead it performs a
series of assertions using JUnit's Assert class. There can be as
few or as many assertions as you like. By using these assertions
it's possible to give users of the class clear information that
can be used to debug tests.

With a little rework, our PageObject looks like:
`load` 方法用于导航到页面,
而 `isLoaded` 方法用于判断我们是否位于正确的页面.
虽然该方法看起来像是应该返回 boolean,
但实际上它通过 JUnit 的 Assert 类执行一系列断言.
断言可以多也可以少. 通过这些断言,
可以为类的使用者提供清晰的调试信息,
用于定位测试失败的原因.

稍作改造后, 我们的页面对象如下:

```java
package com.example.webdriver;
Expand Down Expand Up @@ -243,37 +240,36 @@ public class EditIssue extends LoadableComponent<EditIssue> {
field.sendKeys(text);
}
}

```

That doesn't seem to have bought us much, right? One thing it has done
is encapsulate the information about how to navigate to the page into
the page itself, meaning that this information's not scattered through
the code base. It also means that we can do this in our tests:
看起来似乎没带来太多好处, 对吧?
不过它确实把如何导航到该页面的信息封装进了页面本身,
这意味着这些信息不会散落在代码库各处.
这也意味着我们可以在测试中这样做:

```java
EditIssue page = new EditIssue(driver).get();
```

This call will cause the driver to navigate to the page if that's necessary.
上述调用会在必要时促使 driver 导航到该页面.

### Nested Components
### 嵌套组件

LoadableComponents start to become more useful when they are used in
conjunction with other LoadableComponents. Using our example, we could
view the "edit issue" page as a component within a project's website
(after all, we access it via a tab on that site). You also need to be
logged in to file an issue. We could model this as a tree of nested components:
当 LoadableComponent 与其他 LoadableComponent 配合使用时,
会更加有用. 以我们的例子为例,
我们可以把“编辑 issue”页面视为项目网站中的一个组件(毕竟我们是通过该网站的某个选项卡访问它).
并且提交 issue 需要登录. 我们可以把它建模为一棵嵌套组件树:

```
+ ProjectPage
+---+ SecuredPage
+---+ EditIssue
```

What would this look like in code? For a start, each logical component
would have its own class. The "load" method in each of them would "get"
the parent. The end result, in addition to the EditIssue class above is:
这在代码中会是什么样子?
首先, 每个逻辑组件都有自己的类.
每个类的 `load` 方法会调用父组件的 `get` 方法.
最终效果, 除了上面的 EditIssue 类外, 还包括:

ProjectPage.java:

Expand Down Expand Up @@ -307,8 +303,8 @@ public class ProjectPage extends LoadableComponent<ProjectPage> {
}
}
```

and SecuredPage.java:
以及 SecuredPage.java:

```java
package com.example.webdriver;
Expand Down Expand Up @@ -365,7 +361,7 @@ public class SecuredPage extends LoadableComponent<SecuredPage> {
}
```

The "load" method in EditIssue now looks like:
EditIssue 中的 `load` 方法现在如下:

```java
@Override
Expand All @@ -376,8 +372,10 @@ The "load" method in EditIssue now looks like:
}
```

This shows that the components are all "nested" within each other.
A call to `get()` in EditIssue will cause all its dependencies to load too. The example usage:

这表明这些组件都是相互 "嵌套" 的.
在 EditIssue 中调用 `get()` 会导致它的所有依赖组件也被加载.
示例用法:

```java
public class FooTest {
Expand Down Expand Up @@ -409,21 +407,23 @@ public class FooTest {
}
```

If you're using a library such as [Guiceberry](https://github.com/zorzella/guiceberry) in your tests,
the preamble of setting up the PageObjects can be omitted leading to nice, clear, readable tests.
如果在测试中使用像 [Guiceberry](https://github.com/zorzella/guiceberry) 这样的库,
设置页面对象的前置步骤可以省略, 从而使测试更简洁、可读.


## Bot 模式

## Bot Pattern

(previously located: https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests)
(原位置: https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests

Although PageObjects are a useful way of reducing duplication in your tests,
it's not always a pattern that teams feel comfortable following.
An alternative approach is to follow a more "command-like" style of testing.

A "bot" is an action-oriented abstraction over the raw Selenium APIs.
This means that if you find that commands aren't doing the Right Thing
for your app, it's easy to change them. As an example:
尽管页面对象是减少测试重复的一种有效方式,
但并非所有团队都愿意或适应这种模式.
另一种可选的方式是采用更加 "命令式" 的测试风格.


“bot” 是对底层 Selenium API 的一种面向动作的抽象.
这意味着如果发现某些命令不适合你的应用, 可以轻松修改它们. 例如:

```java
public class ActionBot {
Expand Down Expand Up @@ -454,15 +454,16 @@ public class ActionBot {
}
```

Once these abstractions have been built and duplication in your tests
identified, it's possible to layer PageObjects on top of bots.

一旦构建了这些抽象并找出测试中的重复,
就可以在 bot 之上再封装 页面对象.


## Example
## 示例

{{< tabpane text=true >}}
{{< tab header="Python" >}}
一个用例 使用 `python + pytest + selenium` 实现了设计策略 "**Action Bot**, **Loadable Component** 和 **Page Object**".
一个用例 使用 `python + pytest + selenium` 实现了设计策略 "**Action Bot**, **Loadable Component** 和 **页面对象**".

A `pytest` fixture `chrome_driver`.

Expand All @@ -486,7 +487,7 @@ A `pytest` fixture `chrome_driver`.
{{< /tabpane >}}


"**Action Bot**" implementation.
"**Action Bot**" 实现.

{{< tabpane text=true >}}
{{< tab header="Python" >}}
Expand All @@ -510,7 +511,7 @@ A `pytest` fixture `chrome_driver`.
{{< /tabpane >}}


"**Loadable Component** definition.
"**Loadable Component** 定义.

{{< tabpane text=true >}}
{{< tab header="Python" >}}
Expand All @@ -534,7 +535,7 @@ A `pytest` fixture `chrome_driver`.
{{< /tabpane >}}


"**Loadable Component** and **Page Object**" implementation.
"**Loadable Component** 以及 **页面对象**" 实现.

{{< tabpane text=true >}}
{{< tab header="Python" >}}
Expand All @@ -557,7 +558,7 @@ A `pytest` fixture `chrome_driver`.
{{< /tab >}}
{{< /tabpane >}}

Test cases implementation.
测试用例实现.

{{< tabpane text=true >}}
{{< tab header="Python" >}}
Expand Down
Loading