敏捷實踐(4) - 我們是如何改進AC

敏捷實踐(1) 中,出于介紹目的衔彻,測試用例實現的都相對簡單。

而實際上驗收標準測試用例也并不復雜,百分之八九十的動作無非是:

  • 跳轉某個界面
  • 在某個輸入框輸入一些內容
  • 點擊某個按鈕
  • 檢測某些文本
  • 判斷是否處于某個界面
  • 判斷是否有彈出框徐钠,提示文本

而這些動作(step), cucumber是可以用正則表達式進行標準化處理役首,在然后在各個測試用例中重用。

改進郵箱登錄故事AC需要用到的Step


$cat features/US004_login_by_email.feature

Feature: US_004 郵箱登錄
  為了正常使用需要登錄身份的功能
  作為一個已經用郵箱注冊過的用戶
  我想要用郵箱和密碼登錄系統(tǒng)

  @reset_driver
  Scenario: AC_US004_02 登錄錯誤: 正確郵箱+錯誤密碼登錄
    Given 我已經用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    When 我在 "主頁面" 點擊 "登錄/注冊" 進入 "登錄頁面"
    And 我在 "郵箱或手機" 輸入 "test_user@mytest.com"
    And 我在 "密碼" 輸入 "b123456"
    And 我按下按鈕 "登錄"
    Then 我應當看到浮動提示 "用戶密碼不匹配"
.....

$ cat features/step_definitions/steps.rb

Given(/^我已經用郵箱 (.*) 與密碼 (.*) 注冊過賬號$/) do |email, password|
  # sleep(1)
  puts "DEBUG: email: #{email}"
  puts "DEBUG: password: #{password}"
end

When(/^我在 "主頁面" 點擊 "登錄\/注冊" 進入 "登錄頁面"$/) do
  # 等待主頁面就緒, 主頁面ID 為 home_page
  wait { id('home_page') }
  # 點擊 主頁面中的 '登錄/注冊' 按鈕显拜,按鈕ID為 btn_to_login
  id('btn_to_login').click

  # 檢查頁面跳轉到 登錄頁面衡奥, 登錄頁面ID為 page_login_account
  wait { id('page_login_account') }
end

When(/^我在 "(.*?)" 輸入 "(.*?)"$/) do |input_field, input_value|
  input_id = case input_field
               when '郵箱或手機'
                 'input_username'
               when '密碼'
                 'input_password'
               else
                 'unknown'
             end
  input_box = id(input_id)           # 定位指定的輸入框
  input_box.clear                    # 清除原來的內容
  input_box.type "#{input_value}\n"  # 輸入新內容并回車
end

And(/^我按下按鈕 "登錄"$/) do
  id('btn_login').click
end

Then(/^我應當看到浮動提示 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  wait { find(msg) }
end

Then(/^我應當到達 "主頁面"$/) do
  wait { id('home_page') }
end

And(/^等待 (\d+) 秒后.*/) do |seconds|
  sleep(seconds.to_i)
end

.

When 我在 "主頁面" 點擊 "登錄/注冊" 進入 "登錄頁面"


這個step的目的是我們要在某個界面,點擊 某個組件(按鈕或鏈接)远荠,跳轉到另一個頁面矮固。

When(/^我在 "主頁面" 點擊 "登錄\/注冊" 進入 "登錄頁面"$/) do
  # 等待主頁面就緒, 主頁面ID 為 home_page
  wait { id('home_page') }
  # 點擊 主頁面中的 '登錄/注冊' 按鈕,按鈕ID為 btn_to_login
  id('btn_to_login').click

  # 檢查頁面跳轉到 登錄頁面譬淳, 登錄頁面ID為 page_login_account
  wait { id('page_login_account') }
end

這里面有三個小動作:

  1. 確定當前是否在指定界面档址,是通過查找某個該界面中特有的組件id是否存在來判斷。
  2. 點擊 某個元素邻梆, 是通過查找到指定id的組件守伸,向它發(fā)送click信號。
  3. 判斷當前界面是否是指定界面, 同 1 浦妄。

因此每個界面尼摹,我們都設置一個能夠標識該界面的一個唯一的id见芹,便于我們識別當前的界面。
其次每個需要測試交互的組件蠢涝,都分配一個在該頁面唯一的id玄呛。
最后,為上面的硬編碼id改為對照方式. step改為正則匹配和二。

# When(/^我在 "主頁面" 點擊 "登錄\/注冊" 進入 "登錄頁面"$/) do
When(/^我在 "([^"]*)" 點擊 "(.*?)" 進入 "(.*?)"$/) do |location, button, dest|
  VIEW_MAPPING = {
    '主頁面' => 'home_page',
    '密碼登錄頁面' =>  'page_login_account' 
  }

  BUTTON_MAPPING = {
    '登錄/注冊' => 'btn_to_login'
  }

  location_id = VIEW_MAPPING[location]
  button_id = BUTTON_MAPPING[button]
  dest_id = VIEW_MAPPING[dest]

  wait do
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  end

  wait do
    puts "DEBUG: #{button} => #{button_id}"
    id(button_id)
  end
  id(button_id).click

  wait do
    puts "DEBUG: #{dest} => #{dest_id}"
    id(dest_id)
  end
end

這個steps基本已經通用了徘铝。
只要feature中按照 我在 "AAA" 點擊 "BBB" 進入 "CCC" 這個格式寫測試步驟,都能匹配處理惯吕。

還有不足的的地方庭砍,每次新加按鈕或頁面id時,都需要進入該step中添加混埠,而且怠缸,其他地方無法重用這些映射定義;另一個是 "=>" 這種映射寫法钳宪,通不過Rubocop的語法檢測揭北。

繼續(xù)優(yōu)化


把 VIEW_MAPPING BUTTON_MAPPING 移到一個新文件,作為全局的常量(其實Ruby中并沒有真正的常量定義)吏颖。 并且搔体,反轉映射寫法以滿足Rubocop。
Cucumber會自動加載 features/step_definitions 中所有的文件半醉,無需自己手動require.

$ cat features/step_definitions/keyword_mapping.rb

##
# 1. 按所在頁面進行分類排序
# 2. 不同頁面存在相同關鍵字(button或input), id應相同
# 3. 在下面注釋中出現 '已被定義' 的前綴疚俱, 是為說明相同的關鍵字,在所處hash中已被定義缩多,不需要重新定義

VIEW_MAPPING = {
    home_page: '主頁面',
    page_more_races: '更多賽事頁面',
    page_login_account: '密碼登錄頁面',
    page_login_code: '驗證碼登錄頁面',
    ....
}.invert

BUTTON_MAPPING = {
    # 主頁面
    btn_to_login: '登錄/注冊',
    btn_races_1: '第一個賽事',
    btn_race_detail: '賽事詳情',
    btn_order: '訂單',
    btn_setup: '設置',
    btn_account_security: '賬號安全',
    btn_change_password: '修改密碼',
    btn_more_races: '更多賽事',

    # 密碼登錄頁面
    btn_bar_right: '注冊',
    btn_bar_left: '左上',
    ...
}.invert

改進界面輸入的步驟呆奕,模版化


When(/^我在 "(.*?)" 輸入 "(.*?)"$/) do |input_field, input_value|
  input_id = case input_field
               when '郵箱或手機'
                 'input_username'
               when '密碼'
                 'input_password'
               else
                 'unknown'
             end
  input_box = id(input_id)           # 定位指定的輸入框
  input_box.clear                    # 清除原來的內容
  input_box.type "#{input_value}\n"  # 輸入新內容并回車
end

由于一開始我們就使用了正則匹配,僅是在ID這塊做了條件硬編碼衬吆,該為映射處理:

When(/^我在 "(.*?)" 輸入 "(.*?)"$/) do |input, value|
  input_id = INPUT_MAPPING[input]
  puts "DEBUG: #{input} => #{input_id}"
  input_box = nil
  wait do
    input_box = id(input_id)
  end
  input_box.clear                # 定位指定的輸入框
  input_box.type "#{value}\n".   # 輸入新內容并回車
  sleep 1                        # 輸入完等待1秒梁钾,給模擬器留處理時間
end

為 features/step_definitions/keyword_mapping.rb 添加 INPUT_MAPPING

INPUT_MAPPING = {
    # 密碼登錄頁面
    input_username: '郵箱或手機',
    input_password: '密碼',

    # 驗證碼登錄頁面
    input_phone: '手機號',
    input_code: '驗證碼',

    # 手機注冊頁面
    # 已被定義:手機號,驗證碼

    # 郵箱注冊頁面
    input_email: '郵箱',

    # 實名認證
    input_real_name: '真實姓名',
    input_id_card: '身份證號',

    # 修改密碼
    input_old_pwd: '舊密碼',
    input_new_pwd: '新密碼',
    # 賽事
    input_keyword: '賽事關鍵字',
}.invert

繼續(xù)改進剩余step

And(/^我按下按鈕 "登錄"$/) do
  id('btn_login').click
end

Then(/^我應當看到浮動提示 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  wait { find(msg) }
end

Then(/^我應當到達 "主頁面"$/) do
  wait { id('home_page') }
end

==>

And(/^我[按下|點擊]+按鈕 "(.*?)"$/) do |button|
  button_id = BUTTON_MAPPING[button]
  wait do
    puts "DEBUG: '#{button}' => #{button_id}"
    element = id(button_id)
    puts "DEBUG: got button: #{button_id}, #{element}"
  end
  id(button_id).click
end

Then(/^我應當看到浮動提示 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  wait { find(msg) }
end

Then(/^我應當到達 "([^"]*)"$/) do |location|
  location_id = VIEW_MAPPING[location]
  wait do
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  end
end

備注:Cucumber的Step定義中逊抡, And Given Then When 這四個都是等價的語法糖姆泻,Then 定義的步驟,可以直接在其他步驟中使用冒嫡。

And(/^我應當看到浮動提示 "(.+)"$/) do |msg|
When(/^我應當看到浮動提示 "(.+)"$/) do |msg|
Then(/^我應當看到浮動提示 "(.+)"$/) do |msg|
Given(/^我應當看到浮動提示 "(.+)"$/) do |msg|

這四種都是等價的拇勃。

完整示例


當我們把常用的Step整理后, 基本上已經能滿足95%以上的測試用例編寫孝凌,就連產品方咆,設計也能愉快的按著寫AC了
這個step定義,基本可以直接拿去使用胎许,請叫我 紅領巾峻呛。

$ cat features/step_definitions/steps.rb

Given(/^我已經用郵箱 (.*) 與密碼 (.*) 注冊過賬號$/) do |email, password|
  # sleep(1)
  puts "DEBUG: email: #{email}"
  puts "DEBUG: password: #{password}"
end

Given(/^我在 "([^"]*)" 點擊 "(.*?)" 進入 "(.*?)"$/) do |location, button, dest|
  location_id = VIEW_MAPPING[location]
  button_id = BUTTON_MAPPING[button]
  dest_id = VIEW_MAPPING[dest]

  wait do
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  end

  wait do
    puts "DEBUG: #{button} => #{button_id}"
    id(button_id)
  end
  id(button_id).click

  wait do
    puts "DEBUG: #{dest} => #{dest_id}"
    id(dest_id)
  end
end

When(/^我點擊 "([^"]*)" [進入|回到]+ "(.*?)"$/) do |button, dest|
  button_id = BUTTON_MAPPING[button]
  dest_id = VIEW_MAPPING[dest]
  wait do
    puts "DEBUG: #{button} => #{button_id}"
    element = id(button_id)
    puts "DEBUG: got button: #{button_id}, #{element}"
  end
  id(button_id).click

  wait do
    puts "DEBUG: #{dest} => #{dest_id}"
    id(dest_id)
  end
end

When(/^我[按下|點擊]+按鈕 "(.*?)"$/) do |button|
  button_id = BUTTON_MAPPING[button]
  wait do
    puts "DEBUG: '#{button}' => #{button_id}"
    element = id(button_id)
    puts "DEBUG: got button: #{button_id}, #{element}"
  end
  id(button_id).click
end

When(/^點擊原生button "(.*?)"$/) do |button|
  wait do
    puts "DEBUG: #{button}"
    element = id(button)
    puts "DEBUG: got button: #{element}"
  end
  id(button).click
end

Given(/^我在 "(.*?)" 輸入 "(.*?)"$/) do |input, value|
  input_id = INPUT_MAPPING[input]
  puts "DEBUG: #{input} => #{input_id}"
  input_box = nil
  wait do
    input_box = id(input_id)
  end
  input_box.clear
  input_box.type "#{value}\n"
  sleep 1
end

And(/^等待 (\d+) 秒后.*/) do |seconds|
  sleep(seconds.to_i)
end

Then(/^我應當看到浮動提示 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  wait { find(msg) }
end

Then(/^我應當到達 "([^"]*)"$/) do |location|
  location_id = VIEW_MAPPING[location]
  wait do
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  end
end

Given(/^我在 "([^"]*)"$/) do |location|
  location_id = VIEW_MAPPING[location]
  wait do
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  end
end

Given(/.*\(創(chuàng)建數據\)$/) do |table|
  params = table.hashes.first
  ac = params.delete('ac').downcase
  result = RemoteFactory.create(ac, params)
  puts result.parsed_body
end

Given(/^我已使用 "([^"]*)" 登錄$/) do |value|
  result = RemoteFactory.create('ac_us001', email: value)
  puts result.parsed_body
  puts '回到主頁'
  id(BUTTON_MAPPING['回到主頁']).click if exists { id(BUTTON_MAPPING['回到主頁']) }

  to_login = BUTTON_MAPPING['登錄/注冊']
  wait do
    puts '登錄/注冊'
    id(to_login).click
  end

  email_input = INPUT_MAPPING['郵箱或手機']
  password_input = INPUT_MAPPING['密碼']
  login = BUTTON_MAPPING['登錄']
  wait do
    id(email_input)
  end
  id(email_input).clear
  id(email_input).type "#{value}\n"
  sleep 1

  id(password_input).clear
  id(password_input).type 'test123'
  sleep 1

  id(login).click
end

Given(/^退出登錄$/) do
  puts '回到主頁'
  id(BUTTON_MAPPING['回到主頁']).click if exists { id(BUTTON_MAPPING['回到主頁']) }

  bar_left = BUTTON_MAPPING['左上']
  wait do
    puts '左上'
    id(bar_left).click
  end

  setup = BUTTON_MAPPING['設置']
  wait do
    puts '設置'
    id(setup).click
  end

  btn_exit = BUTTON_MAPPING['退出登錄']
  wait do
    puts '退出登錄'
    id(btn_exit).click
  end

  id('確定').click
end

Given(/^清除數據$/) do
  result = RemoteFactory.create('clear')
  puts result.parsed_body
end

Then(/^我應當看到 "(.*?)" 顯示 "(.+)"$/) do |location, msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  location_id = INPUT_MAPPING[location]
  wait {
    puts "DEBUG: #{location} => #{location_id}"
    id(location_id)
  }
  id(location_id).value.eql?(msg)
end

Then(/^"([^"]*)" 按鈕置灰罗售,無法點擊$/) do |button_text|
  pending
end

Then(/^"([^"]*)" 按鈕無法點擊$/) do |button_text|
  pending
end

Then(/^看到的 "([^"]*)" 應為 "([^"]*)"$/) do |text_name, value|
  text_id = TEXT_MAPPING[text_name]
  wait {
    puts "DEBUG: #{text_name} => #{text_id}"
    id(text_id)
  }

  target_value = id(text_id).value.strip
  puts "DEBUG: #{target_value} eql? #{value}"
  raise unless target_value.eql?(value)
end

Then(/^我能看到 "([^"]*)" 這些元素$/) do |elements|
  elements.split(',').each do |element|
    element
    id(TEXT_MAPPING[element])
  end
end

And(/^我在Alert中點擊 "(.+)"$/) do |button_text|
  wait(1) do
    tag('UIAAlert')
    button(button_text).click
  end
end

And(/^上傳圖片$/) do
  id('btn_picker_image').click
  wait(10) do
    id('圖庫').click
  end
  wait(10) do
    id('好').click
  end
  wait(10) do
    id('Camera Roll').click
  end
  wait do
    tag('XCUIElementTypeCell').click
  end
  sleep 1
end

Then(/^隱藏鍵盤$/) do
  hide_keyboard('Return')
end

And(/^打印調試 (.+)$/) do |debug_name|
  debug_name.strip!
  if debug_name == 'page'
    page
  elsif debug_name == 'source'
    source
  end
end

Then(/^"([^"]*)" 應隱藏/) do |button_text|
  pending
end

Then(/^我能看到 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  find(msg)
end

And(/^上滑$/) do
  # swipe start_x: 300, start_y: 300, offest_x: 0, offset_y: -200
  swipe direction: 'up'
end

And(/^下拉刷新$/) do
  # swipe start_x: 300, start_y: 300, offest_x: 0, offset_y: 200
  swipe direction: 'down'
  sleep 1
end

Then(/^我應該找不到 "([^"]*)" 這些元素$/) do |elements|
  elements.split(',').each do |element|
    raise "存在#{element}這個元素" if exists { id(TEXT_MAPPING[element]) }
  end
end

Then(/^應不存在 "([^"]*)"$/) do |button|
  raise "存在#{button}" if exists { id(BUTTON_MAPPING[button]) }
end

Then(/^在 "([^"]*)" 可匹配到 "([^"]*)"$/) do |button, element|
  button_id = BUTTON_MAPPING[button]
  label = ''
  wait do
    puts "DEBUG: #{button} => #{button_id}"
    label = id(button_id).label
    puts "DEBUG: got label: #{label}"
  end
  raise "未匹配到#{element}" unless label.match(element)
end

Then(/^pending:.*$/) do
  pending
end

完整用戶故事例子

US_001 郵箱注冊


Feature: US_001 郵箱注冊
  作為一名非注冊用戶,我需要用郵箱號钩述,使得我可以完成注冊

  @reset_driver
  Scenario: AC_US001_01 注冊錯誤: 錯誤郵箱注冊
    Given 我在 "主頁面"
    When 我在 "主頁面" 點擊 "登錄/注冊" 進入 "密碼登錄頁面"
    And 我點擊 "注冊" 進入 "手機注冊頁面"
    And 我點擊 "使用郵箱注冊" 進入 "郵箱注冊頁面"
    And 我在 "郵箱" 輸入 "aa@desh"
    And 我在 "密碼" 輸入 "test123"
    And 我按下按鈕 "完成"
    Then 我應當看到浮動提示 "您的電子郵件格式不正確"

  Scenario: AC_US001_02 下一步按鈕是灰色狀態(tài)
    Given 我在 "郵箱" 輸入 ""
    Then "完成" 按鈕置灰寨躁,無法點擊

  Scenario: AC_US001_03 成功跳轉到 手機注冊頁面
    Given 我在 "郵箱注冊頁面"
    When 我按下按鈕 "使用手機注冊"
    Then 我應當到達 "手機注冊頁面"

  Scenario: AC_US001_04 成功跳轉到 密碼登錄頁面
    Given 我點擊 "使用郵箱注冊" 回到 "郵箱注冊頁面"
    When 我按下按鈕 "我已有賬號"
    Then 我應當到達 "密碼登錄頁面"

  Scenario: AC_US001_05 注冊錯誤 郵箱已注冊
    Given 我已經用郵箱 test@gmail.com 注冊過賬號 (創(chuàng)建數據)
      | ac       | clear | email          |
      | AC_US001 | true  | test@gmail.com |
    When 我點擊 "注冊" 進入 "手機注冊頁面"
    And 我點擊 "使用郵箱注冊" 回到 "郵箱注冊頁面"
    And 我在 "郵箱" 輸入 "test@gmail.com"
    And 我在 "密碼" 輸入 "test123"
    And 我按下按鈕 "完成"
    Then 我應當看到浮動提示 "郵箱已被使用"

#  Scenario: AC_US001_06  備注:重復ac,與AC_US001_01重復

  Scenario: AC_US001_07 注冊錯誤 密碼格式錯誤
    Given 我在 "郵箱" 輸入 "test@gmail.com"
    When 我在 "密碼" 輸入 "123456"
    And 我按下按鈕 "完成"
    Then 我應當看到浮動提示 "密碼格式不正確"

  Scenario: AC_US001_08 注冊成功
    Given 我在 "郵箱" 輸入 "test1@gmail.com"
    When 我在 "密碼" 輸入 "test123456"
    And 我按下按鈕 "完成"
    Then 我應當到達 "主頁面"

US-006 忘記密碼-郵箱找回

Feature: US-006 忘記密碼-郵箱找回
  作為一名忘記密碼的用戶,我需要用已認證的郵箱, 使得我能夠找回密碼

  @reset_driver
  Scenario: AC-US006-01 沒有任何輸入
    Given 我在 "主頁面" 點擊 "登錄/注冊" 進入 "密碼登錄頁面"
    And 我點擊 "忘記密碼" 進入 "忘記密碼頁面"
    And 我按下按鈕 "使用郵箱找回密碼"
    Then "下一步" 按鈕置灰牙勘,無法點擊

  Scenario: AC-US006-02 沒有任何輸入 點擊獲取驗證碼
    When 我按下按鈕 "獲取驗證碼"
    Then 我應當看到浮動提示 "您的電子郵件格式不正確"

  Scenario: AC-US006-03 錯誤格式的郵箱 點擊獲取驗證碼
    And 我在 "郵箱" 輸入 "test@aa"
    And 我按下按鈕 "獲取驗證碼"
    Then 我應當看到浮動提示 "您的電子郵件格式不正確"

  Scenario: AC-US006-04 錯誤格式的郵箱 點擊獲取驗證碼
    And 我在 "郵箱" 輸入 "ricky@aa"
    And 我按下按鈕 "獲取驗證碼"
    Then 我應當看到浮動提示 "您的電子郵件格式不正確"

#  Scenario: AC_US006_05  備注:重復ac,與AC_US006_07重復

  Scenario: AC-US006-06 未輸入郵箱 但輸入了驗證碼
    When 我在 "郵箱" 輸入 ""
    And 我在 "驗證碼" 輸入 "aaa"
    And 我按下按鈕 "獲取驗證碼"
    Then 我應當看到浮動提示 "您的電子郵件格式不正確"

  Scenario: AC-US006-07 輸入正確的郵箱 及正確的驗證碼
    Given 我已經用郵箱 test@aa.com 注冊過賬號 (創(chuàng)建數據)
      |ac         |clear|email|
      |AC_US006_07|true |test@aa.com|
    And 我在 "郵箱" 輸入 "test@aa.com"
    And 我按下按鈕 "獲取驗證碼"
    And 我在 "驗證碼" 輸入 "123456"
    And 隱藏鍵盤
    And 我按下按鈕 "下一步"
    Then 我應當到達 "輸入密碼頁面"

  Scenario: AC-US006-08 輸入正確的郵箱 及正確的驗證碼
    Given 我已經用郵箱 test@aa.com 注冊過賬號 (創(chuàng)建數據)
      |ac         |clear|email|
      |AC_US006_08|true |test@aa.com|
    And 我在 "密碼" 輸入 "123456"
    And 我按下按鈕 "完成"
    Then 我應當看到浮動提示 "密碼格式不正確"

  Scenario: AC-US006-09 輸入正確的郵箱 及正確的驗證碼
    Given 我按下按鈕 "回到主頁"
    When 我在 "主頁面" 點擊 "登錄/注冊" 進入 "密碼登錄頁面"
    And 我點擊 "忘記密碼" 進入 "忘記密碼頁面"
    And 我按下按鈕 "使用郵箱找回密碼"
    And 我在 "郵箱" 輸入 "test@aa.com"
    And 我按下按鈕 "獲取驗證碼"
    And 我在 "驗證碼" 輸入 "123456"
    And 我按下按鈕 "下一步"
    And 我在 "密碼" 輸入 "a123456"
    And 我按下按鈕 "完成"
    Then 我應當到達 "密碼登錄頁面"

最后职恳,為了確保測試用例每次都能正確,我們專門部署一個后端持續(xù)集成版本方面,額外提供了一組用于重置/創(chuàng)建測試用例數據放钦,用于支持APP測試。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末恭金,一起剝皮案震驚了整個濱河市操禀,隨后出現的幾起案子,更是在濱河造成了極大的恐慌横腿,老刑警劉巖颓屑,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異耿焊,居然都是意外死亡揪惦,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門罗侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來器腋,“玉大人,你說我怎么就攤上這事钩杰∪宜” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵榜苫,是天一觀的道長护戳。 經常有香客問我,道長垂睬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任抗悍,我火速辦了婚禮驹饺,結果婚禮上,老公的妹妹穿的比我還像新娘缴渊。我一直安慰自己赏壹,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布衔沼。 她就那樣靜靜地躺著蝌借,像睡著了一般昔瞧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菩佑,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天自晰,我揣著相機與錄音,去河邊找鬼稍坯。 笑死酬荞,一個胖子當著我的面吹牛,可吹牛的內容都是我干的瞧哟。 我是一名探鬼主播混巧,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勤揩!你這毒婦竟也來了咧党?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤陨亡,失蹤者是張志新(化名)和其女友劉穎傍衡,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體数苫,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡聪舒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了虐急。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箱残。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖止吁,靈堂內的尸體忽然破棺而出被辑,到底是詐尸還是另有隱情,我是刑警寧澤敬惦,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布盼理,位于F島的核電站,受9級特大地震影響俄删,放射性物質發(fā)生泄漏宏怔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一畴椰、第九天 我趴在偏房一處隱蔽的房頂上張望臊诊。 院中可真熱鬧,春花似錦斜脂、人聲如沸抓艳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玷或。三九已至儡首,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間偏友,已是汗流浹背蔬胯。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留约谈,地道東北人笔宿。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像棱诱,于是被迫代替她去往敵國和親泼橘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容