2017-03-03 46 views
0

一个模块的方法的请求我在Rails API下列模块:RSpec的测试依赖于返回的随机数

module SpeedCalculator 

    def self.adjustment 
    Random.rand(0..0.3) 
    end 

    def self.calculate_adjustment(track, car_speed) 
    case track.surface_type 
     when "asphalt" 
     car_speed - (car_speed * self.adjustment).ceil 
     when "gravel" 
     car_speed - (car_speed * self.adjustment).ceil 
     when "snow" 
     car_speed - (car_speed * self.adjustment).ceil 
     else 
     car_speed 
    end 
    end 
end 

我可以成功地测试该调整方法是这样的:

require 'rails_helper' 

RSpec.describe SpeedCalculator do 
    include SpeedCalculator 

    it "uses an adjustment value between 0 and 0.3" do 
    expect(SpeedCalculator.adjustment).to be >= 0 
    expect(SpeedCalculator.adjustment).to be <= 0.3 
    end 
end 

有可能作出这样的API请求:

本地主机:3000/API/V1 /汽车/保时捷911轨=摩纳哥

您要求系统计算给定轨道上给定汽车的速度。

所以我需要编写一个请求规范,对于给定的汽车和轨道,返回正确的值。但是如果calculate_adjustment总是应用一个随机数,我该怎么做呢?

我相信,我需要创建一个self.adjustment模拟/存根,因此测试将是这样的:

it "calculates max_speed_on_track when a valid track name is provided" do 
     Car.create!(name:'Subaru Impreza', max_speed:'120', speed_unit:'km/h') 
     Track.create(name:'Monaco') 

     # here create a dummy version of adjustment 
     # that always returns a fixed value, rather than a random value 
     # and somehow use that dummy for the request? 
     # Since x below needs to be a known value for the test to work. 

     get api_v1_car_path(id: 'porsche-911', track: 'monaco')  
     expect(response).to have_http_status(200) 
     expect(response.body).to include_json(car: {max_speed_on_track: x})  
    end 

回答

2

我该怎么做,当calculate_adjustment总是应用随机数?

我相信,我需要创建一个模拟/存根self.adjustment

究竟!你想要测试的最后一件事是随机行为(和随机失败)。你想要可重现的结果。所以是的,嘲笑你的RNG。

简单事情会是这样:

expect(Random).to receive(:rand).with(0..0.3).and_return(0.1234) 
# or better 
expect(SpeedCalculator).to receive(:adjustment).and_return(0.1234) 

# then proceed with your test 
get api_v1_car_path(id: 'porsche-911', track: 'monaco') 
... 

进一步改善这里是不使用控制器的规格来测试业务逻辑。将您的业务逻辑封装在一个对象中并测试该对象(您可以在其中最大限度地使用依赖注入技术)。而你的控制器会变成这样的:

class CarsController 
    def show 
    calculator = MaxSpeedCalculator.new(params[:id], params[:track]) 
    render json: calculator.call 
    end 
end 
+0

但这是我的问题 - 我该如何嘲笑它? – rmcsharry

+0

我打算编写单独的测试来测试模块中的方法。 REQUEST规范将测试返回正确的json,就是这样。我只是不知道如何让该请求使用模拟调整方法而不是模块中的随机调整方法。另外,在你的控制器例子中,什么是“呼叫”正确呼叫? – rmcsharry

+0

在我的例子中,'call'是'MaxSpeedCalculator'对象的一个​​方法,它返回一个散列。 –