【问题标题】:Flaky tests with redis使用 redis 进行易碎测试
【发布时间】:2019-09-19 20:59:46
【问题描述】:

我有一个单元测试用于在 redis 中缓存 API 密钥(在 rails 应用程序中)。

redis 设置为带有connection_pool gem 的全局变量($redis)。所以我做$redis.with do |redis| 来实际获得redis 连接。

问题是,我的测试非常不稳定。它有两个断言:一个用于测试获取预期值,另一个用于测试该值是否已缓存(10 分钟)。

jwt = JWT.encode payload, private_key, "RS256"
assert_equal jwt, Foo.app_token
travel 5.minutes
assert_equal jwt, Foo.app_token

我无法弄清楚为什么测试如此不稳定。它可能每运行 3-5 次就会失败。任何帮助将不胜感激。我从来没有真正在连接池中使用过 redis,所以很可能是在做一些基本的错误。

方法的实现:

def app_token
  find_app_token || create_app_token
end

private

def find_app_token
  $redis.with { |redis| redis.get APP_KEY }
end

def create_app_token
  payload = # some payload
  JWT.encode(payload, private_key, "RS256").tap do |jwt|
     $redis.with do |redis|
       redis.set APP_KEY, jwt
       redis.expireat APP_KEY, payload[:exp]
     end
  end
end

【问题讨论】:

  • 我认为这是因为您没有在每次运行后清除 redis。断言后取消设置redis中的值。
  • 啊,我确实有一个拆卸钩子可以冲洗

标签: ruby-on-rails ruby multithreading testing redis


【解决方案1】:

在此处将其作为答案以提高知名度。

travel 5.minutes 存根Time.now 和其他相关方法以根据所需的持续时间增加/减少时间。 在测试结束时删除存根。我认为他们的意思是在整个测试套件执行结束时。这可能是导致片状测试的可能原因。

travel 还提供了一个选项来提供一个块,然后重置存根。 因此,像

travel 5.minutes do
 assert_equal jwt, Foo.app_token
end

可能是一种更合适的方法,因为它会在检查所需的断言后立即删除存根。 更多在这里: https://api.rubyonrails.org/v6.0.0/classes/ActiveSupport/Testing/TimeHelpers.html#method-i-travel

【讨论】:

    【解决方案2】:

    我已经删除了travel 5.minutes 语句,并且测试似乎现在可以工作了,没有剥落。 ?‍♂️

    【讨论】:

    • 据我了解,travel 应该在断言完成后按时删除存根,我认为这在您的情况下不会发生。你能试试这样的travel 5.minutes { assert_equal jwt, Foo.app_token }
    • 成功了——非常感谢@YuvrajJaiswal。 (旅行在这个测试中实际上在技术上是无用的——这就是为什么我很乐意删除它——因为据我了解,它不会影响 redis 上的 ttl。但是 redis 是我不想要的实现细节测试。所以我现在可以保留travel,我不知道。?)
    猜你喜欢
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 2014-03-19
    • 2020-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多