Describing Features

将特性(features)整理成若干用户故事(User Stories), 可以采用role + action的形式作为故事的标题.
故事里不需要包含太多细节, 详细内容可以在选定好选取哪些故事用作发布以及哪次迭代时发布后, 再行考虑.

  • Code-breaker starts game The code-breaker opens a shell, types a command, and sees a welcome message and a prompt to enter the first guess.
  • Code-breaker submits guess The code-breaker enters a guess, and the system replies by marking the guess according to the marking algorithm.

关于User Stroies, 可以看下iHover大大的User Stories (1) 什麼是 User Story?

User Story需要拥有以下特性:

  • Have business value
  • Be testable
  • Be small enough to implement in one iteration

在项目里添加一个features目录,然后在teatures下添加support目录,
support目录里添加env.rb文件(其实*.rb便可), 这样cucumber会知道我们正在用ruby

在里features面创建一个codebreaker_submits_guess.feature文件

Scenario Example - codebreaker_submits_guess.feature
1
2
3
4
5
6
7
8
9
Feature: code-breaker submits guess
  As a code-breaker
  I want to submit a guess
  So that I can try to break the code

  Scenario: all exact matches
    Given the secret code is "1234"
    When I guess "1234"
    Then the mark should be "++++"
Scenario Outline Example - codebreaker_submits_guess.feature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Feature: code-breaker submits guess
  As a code-breaker
  I want to submit a guess
  So that I can try to break the code

  Scenario Outline: submit guess
    Given the secret code is "<code>"
    When I guess "<guess>"
    Then the mark should be "<mark>"

  Scenarios: all numbers correct
    | code | guess | mark |
    | 1234 | 1234  | ++++ |
    | 1234 | 1243  | ++-- |
    | 1234 | 1423  | +--- |
    | 1234 | 4321  | ---- | 

Automating Features with Cucumber

features目录下创建step_definitions目录, 然后再里面添加一个codebreaker_steps.rb文件

Step Definition Methods

  • Given() 给出背景条件(context)  
  • When() 执行动作  
  • Then() 校验结果  
  • And()与But() 与上一个Given(),When(),或Then()意义相同, 只为使整个描述看起来更近似自然语言.

Describing Code with RSpec

项目下创建spec/codebreaker/, 然后在里面添加game_spec.rb
原则是每个source文件要对应一个spec文件

game_spec.rb
1
2
3
4
5
6
7
8
9
10
require 'spec_helper'

module Codebreaker
  describe Game do
    describe "#start" do
      it "sends a welcome message"
      it "prompts for the first guess"
    end
  end
end

spec/codebreaker/下添加一个spec_helper.rb

spec_helper.rb`
1
require 'codebreaker'

it()方法如果不传入代码块, 会被当做pending的方法

可以用double("xxx")方法得到一个test double(测试替身)
double("xxx").as_null_object会让替身只关心指定给它的被期待的消息, 而忽略其他消息

game_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require 'spec_helper'

module Codebreaker
  describe Game do
    describe "#start" do
      it "sends a welcome message" do
        output = double('output').as_null_object
        game = Game.new(output)

        output.should_receive(:puts).with('Welcome to Codebreaker!')

        game.start
      end

      it "prompts for the first guess" do
        output = double('output').as_null_object
        game = Game.new(output)

        output.should_receive(:puts).with('Enter guess:')

        game.start
      end
    end
  end
end

before(:each) {}
传入block里的内容在每个example的顶部执行
可用这个方法创建实例变量并赋值

1
2
3
4
before(:each) do
  @output = double('output').as_null_object
  @game = Game.new(@output)
end

let(:method) {}
传入的symbol作为方法名, 传入的block被当做方法体

1
2
let(:output) { double('output').as_null_object }
let(:game) { Game.new(output) }

在ActiveAdmin下自定义filter

rails4之后,之前的`model`里加入`search_methods :filter_name`的做法已经失效,需修改为:``` ruby class PromoCode (ids) { with_tags(ids) } def self. …… Continue reading

Mac上搭建Phonegap环境

Published on October 02, 2014

Rails遗留程序里最常犯的错误(译)

Published on July 23, 2014