目录:
框架????????????????????????????????????????说明
TDD????????????????????????????????????????代码风格
DDT????????????????????????????????????????数据驱动风格
ATDD??????????????????????????????????????验收测试驱动开发
BDD????????????????????????????????????????行为驱动开发 (Behavior-driven development)
MBT????????????????????????????????????????Model Based Testing 基于模型的测试
TDD 定义:
TDD 流程:
代表作 JUnit TestNG
@Test
void standardAssertions() {
assertEquals(2, calculator.add(1, 1));
assertEquals(4, calculator.multiply(2, 2),
"The optional failure message is now the last parameter");
assertTrue('a' < 'b', () -> "Assertion messages can be lazily evaluated -- "
+ "to avoid constructing complex messages unnecessarily.");
}
TestNG:
package example1;
import org.testng.annotations.*;
public class SimpleTest {
@BeforeClass
public void setUp() {
// code that will be invoked when this test is instantiated
}
@Test(groups = { "fast" })
public void aFastTest() {
System.out.println("Fast test");
}
@Test(groups = { "slow" })
public void aSlowTest() {
System.out.println("Slow test");
}
}
代表作 Pytest UnitTest
# content of test_sample.py
def inc(x):
return x + 1
def test_answer():
assert inc(3) == 5
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
BDD VS TDD:
BDD:
BDD 与 TDD?
BDD 相关框架:
Cucumber:
?
Cucumber 测试用例 Scenario 场景:
Scenario: Finding some cheese
Given I am on the Google search page
When I search for "Cheese!"
Then the page title should start with "cheese"
Cucumber 测试用例步骤定义:
public class ExampleSteps {
private final WebDriver driver = new FirefoxDriver();
@Given("I am on the Google search page")
public void I_visit_google() {
driver.get("https://www.google.com");
}
@When("I search for {string}")
public void search_for(String query) {
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys(query);
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
}
@Then("the page title should start with {string}")
public void checkTitle(String titleStartsWith) {
// Google's search is rendered dynamically with JavaScript
// Wait for the page to load timeout after ten seconds
new WebDriverWait(driver,10L).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith(titleStartsWith);
}
});
}
@After()
public void closeBrowser() {
driver.quit();
}
}
cucumber 项目结构:
ATDD 定义:
ATDD 相关工具:
?
Robotframework:
Robotframework 介绍:
Robotframework 测试用例:
*** Settings ***
Documentation Simple example using SeleniumLibrary.
Library SeleniumLibrary
*** Variables ***
${LOGIN URL} http://localhost:7272
${BROWSER} Chrome
*** Test Cases ***
Valid Login
Open Browser To Login Page
Input Username demo
Input Password mode
Submit Credentials
Welcome Page Should Be Open
[Teardown] Close Browser
*** Keywords ***
Open Browser To Login Page
Open Browser ${LOGIN URL} ${BROWSER}
Title Should Be Login Page
Input Username
[Arguments] ${username}
Input Text username_field ${username}
Input Password
[Arguments] ${password}
Input Text password_field ${password}
Submit Credentials
Click Button login_button
Welcome Page Should Be Open
Title Should Be Welcome Page
?数据驱动风格:
*** Settings ***
Test Template Login with invalid credentials should fail
*** Test Cases *** USERNAME PASSWORD
Invalid User Name invalid ${VALID PASSWORD}
Invalid Password ${VALID USER} invalid
Invalid User Name and Password invalid invalid
Empty User Name ${EMPTY} ${VALID PASSWORD}
Empty Password ${VALID USER} ${EMPTY}
Empty User Name and Password ${EMPTY} ${EMPTY}
BDD 风格:
*** Test Cases ***
Valid Login
Given login page is open
When valid username and password are inserted
and credentials are submitted
Then welcome page should be open
?ATDD VS BDD:
????????????????TDD? ? ? ? ?????????????????ATDD????????????????????????BDD
受众? ? ? ? ?开发? ? ????????????????? ??开发 测试 客户? ? ? ? ? 开发 测试 客户
过程? ? ? ? ?代码? ? ????????????????? ? DSL? ? ? ? ? ? ? ? ? ? ? ? ? ?行为
目标? ???????代码调用功能? ? ? ? ?验收测试需求?????????????需求
edge 代表步骤:
?vertex 代表断言:
graph 代表测试用例集:
测试用例样板生成:
@Override
public void v_Pet() {
$(By.tagName("h2")).shouldHave(text("Pet"));
}
@Override
public void e_AddPetFailed() {
$(By.id("name")).clear();
$(By.id("birthDate")).clear();
$(By.id("birthDate")).sendKeys("2015/02/05" + Keys.ENTER);
$(By.id("ui-datepicker-div")).shouldBe(not(visible));
$(By.id("type")).selectOption("dog");
$("button[type=\"submit\"]").click();
}
@Override
public void e_VisitAddedFailed() {
$(By.id("description")).clear();
$("button[type=\"submit\"]").click();
}
}
DDT:
DDT 相关工具:
数据驱动应用案例
HttpRunner测试框架:
HttpRunner 测试用例:
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
base_url: "https://postman-echo.com"
verify: False
export: ["foo3"]
teststeps:
- name: get with params
variables:
foo1: bar11
foo2: bar21
sum_v: "${sum_two(1, 2)}"
request:
method: GET
url: /get
params:
foo1: $foo1
foo2: $foo2
sum_v: $sum_v
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
extract:
foo3: "body.args.foo2"
validate:
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "bar11"]
- eq: ["body.args.sum_v", "3"]
- eq: ["body.args.foo2", "bar21"]
- name: post raw text
variables:
foo1: "bar12"
foo3: "bar32"
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "text/plain"
data: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
validate:
- eq: ["status_code", 200]
- eq:
[
"body.data",
"This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
]
- name: post form data
variables:
foo2: bar23
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
validate:
- eq: ["status_code", 200]
- eq: ["body.form.foo1", "$expect_foo1"]
- eq: ["body.form.foo2", "bar23"]
- eq: ["body.form.foo3", "bar21"]
数据驱动风格为什么广受欢迎
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
总结
?
?
?
数据统计
?
?
?
基于测试用例与代码的关联数据分析,实现测试覆盖改进的方法:
阿里云效测试能力与架构
腾讯 WeTest 测试能力全景图:
?