测试 rspec 的作用域问题

jzlikewei · 2014年06月29日 · 最后由 jzlikewei 回复于 2014年06月30日 · 2223 次阅读

最近在做微信公众平台的开发,自动回复这边做了个带状态记录的关键字回复,内容写在 yml 里,类似下面这样:

菜单:
  body: |
    请回复对应功能序号:
    [1]功能1
    [2]功能1
  1:
    body: |
      请回复对应功能序号:
      [A]子功能A
      [B]子功能B
    A:
      body:  AAAAAAA
    B: 
      body:  BBBBBB
  ...

当你依次回复"菜单"、"1"、"A"三个关键字之后,就会得到一串"AAAAA"的回复 本着完全测试的目的,就写了个递归的测试,把整个关键字列表都跑一遍 像下面这样的代码一样

define_method(:recursion_test) do |key,value|
      print auto_reply
      #describe " 响应[#{key}]目录"  do
        it "响应[#{key}]消息" do
          msg_content = user_sent['text_msg']
          msg_content['Content']=key
          msg = Wxmessage.new(msg_content.to_msg)
          expect( get_content(msg.reply) ).to eq(value['body'])
        end
        if value.length>1 #子消息
          #describe '响应子消息' do
            value.each_pair do |k,v|
              recursion_test(k,v)
            end
          #end
        end

      #end
    end

可是,似乎是作用域的问题,整个 rspec 的 DSL 都失效了。 怎样传递作用域?对于类似的情况,怎样更好的测试?

不客气地说,这个测试写得很糟。测试也是要当文档的,是给别人和自己看的,测什么东西,过什么步骤,需要一目了然。测试的代码就是你调用 API 的过程,简洁好用的 API 不需要递归、元编程、循环一大堆逻辑来调用。

就这个具体测试而言,用户输入什么回复,系统就会给出什么回复。这是对系统的要求,所以必须明确定义在测试中,什么流程返回什么信息,不需要过度抽象。如果靠读取系统自己的 key/value 来验证,那样是自己测自己,永远不会出错,也就失去了测试的意义。

我改一下你看怎么样:(有些具体业务逻辑调用不一定对,大致反映个意思)

describe "system responds according to user input" do
  before do
    setup_system # For example instantiate WxMessage 
    user_send '菜单'
    expect(response).to match("请回复对应功能序号")
    user_send "1"
    expect(response).to match("子功能")
  end

  it "responds sub function A" do
    user_send "A"  
    expect(response).to eq("AAAAA")
  end

  it "responds sub function B" do;
    # Do similar 
  end
end

#1 楼 @billy 学习了。 刚刚开始写测试,所以整个测试也是写的十分繁琐,也有待重构。 那是否无法在 spec DSL 中在定义函数然后,在函数里写测试,然后在别处调用,像下面这样

   def just_test(apiname,output)
     it "responds #{apiname} function " do
       call_api_by_name apiname
       expect(response).to eq(output)
     end
   end
...
just_test('name','output')
...

@jzlikewei 可以自定义任何东西的。def、matcher,什么都可以的。但我觉得不通用的没有必要,参数要求独特的也没有必要。如果只用一次的就直接写在代码里,该测试文件可以通用的就写在文件的下面。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号