wechat icon indicating copy to clipboard operation
wechat copied to clipboard

如何用 rspec 测试我的 WechatsController?

Open FrankFang opened this issue 7 years ago • 1 comments

不知是否能在 README.md 加一个 rspec 的例子?

FrankFang avatar Jun 07 '18 04:06 FrankFang

@FrankFang 跟您一样,当时琢磨如何测试WechatsController花了不少时间,代码如下:

require 'rails_helper'
include Wechat::Cipher

def unpack(msg)
  msg_len = msg[16, 4].reverse.unpack('V')[0]
  content = msg[20, msg_len]
  app_id = msg[(20 + msg_len)..-1]
  [content, app_id]
end

RSpec.describe WechatsController, type: :controller do
  let(:token) {
    ENV['MY_WECHAT_APP_TOKEN']
  }

  let(:encoding_aes_key) {
    ENV['MY_WECHAT_APP_ENCODING_AES_KEY']
  }

  let(:appid) {
    ENV['MY_WECHAT_APP_ID']
  }

  let(:message_base) do
    {
      ToUserName: 'toUser',
      FromUserName: 'fromUser',
      CreateTime: '1348831860',
      MsgId: '1234567890123456'
    }
  end

  let(:signature_params) do
    timestamp = '1234567'
    nonce = 'nonce'
    signature = Digest::SHA1.hexdigest([token, timestamp, nonce].sort.join)
    { timestamp: timestamp, nonce: nonce, signature: signature }
  end

  let(:message_base) do
    {
      ToUserName: 'toUser',
      FromUserName: 'fromUser',
      CreateTime: '1348831860',
      MsgId: '1234567890123456'
    }
  end

  let(:text_message) { message_base.merge(MsgType: 'text', Content: 'text message') }

  def signature_echostr(echostr)
    encrypt_echostr = Base64.strict_encode64 encrypt(pack(echostr, appid), encoding_aes_key)
    timestamp = '1234567'
    nonce = 'nonce'
    msg_signature = Digest::SHA1.hexdigest([token, timestamp, nonce, encrypt_echostr].sort.join)
    { timestamp: timestamp, nonce: nonce, echostr: encrypt_echostr, msg_signature: msg_signature }
  end

  def xml_to_hash(response)
    Hash.from_xml(response.body)['xml'].symbolize_keys
  end

  describe 'Verify signature' do
    specify 'on show action' do
      get :show, params: signature_params.merge(signature: 'invalid_signature')
      expect(response.code).to eq('403')
    end

    specify 'on create action' do
      get :show, params: signature_params
      expect(response.code).to eq('200')
    end
  end

  specify 'will respond empty if no responder for the message type' do
    post :create, params: signature_params.merge(xml: text_message)
    expect(response.code).to eq('200')
    expect(response.body.strip).to be_empty
  end

  def send_message(content)
    post :create, params: signature_params.merge(xml: text_message.merge(Content: content))
    encrypted_data = xml_to_hash(response)
    xml_message, appid = unpack(decrypt(Base64.decode64(encrypted_data[:Encrypt]), encoding_aes_key))
    Hash.from_xml(xml_message)['xml']['Content']
  end

  describe 'responder_for' do
    specify "echo 'echostr' param when show" do
      get :show, params: signature_params.merge(echostr: 'hello')
      expect(response.body).to eq('hello')
    end

    specify '公众号回复' do
      expect(send_message 'ping').to eq 'pong'
      expect(send_message '您好').to eq '您好,客服人员正在火速赶来,请稍后...'
    end
  end
end

hophacker avatar Feb 02 '19 06:02 hophacker