使用MiniTest检查模型上的方法调用 [英] Check method call on model using MiniTest

查看:78
本文介绍了使用MiniTest检查模型上的方法调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我使用的是RSpec,则可以测试是否这样调用方法:

If I was using RSpec I could test if a method is being called like so:

expect(obj).to receive(:method)

MiniTest中的等效项是什么?我有一个模型Post,它有一个运行方法create_slugbefore_validation回调.在我的测试test/models/post_test.rb中,我想确保在调用post.save时正在调用create_slug方法.

What is the equivalent in MiniTest? I have a model, Post, which has a before_validation callback which runs a method create_slug. In my test test/models/post_test.rb I want to ensure that the create_slug method is being called when calling post.save.

Minitest :: Spec文档说,我可以使用方法must_send来检查是否调用了方法.但是,当我尝试@post.must_send :create_slug时,出现以下错误:

The Minitest::Spec documentation says that I can use a method must_send to check if a method is called. However, when I try @post.must_send :create_slug I receive the following error:

NoMethodError: undefined method `must_send' for #<Post:0x007fe73c39c648>

我在test_helper.rb文件中包含Minitest :: Spec:

I am including Minitest::Spec in my test_helper.rb file:

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'minitest/spec'

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  #
  # Note: You'll currently still have to declare fixtures explicitly in integration tests
  # -- they do not yet inherit this setting
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

我的测验摘录:

describe Post do
  before do
    @post = FactoryGirl.build(:post)
  end

  describe "when saving" do
    it "calls the create_slug method before validation" do
      @post.must_send :create_slug
      @post.save
    end
  end
end

推荐答案

此处要问的是部分模拟.这意味着您有一个真实的对象,并且您想模拟一种方法并确认它已被调用. Minitest :: Mock不支持开箱即用的部分模拟,但我将尝试向您展示如何实现这一目标.在部分模拟"中进行一两个搜索,看看人们对此有何评论.

What you are asking for here is a partial mock. This means you have a real object and you want to mock out one method and verify it was called. Minitest::Mock does not support partial mocks out of the box, but I'll try to show you how you can accomplish this anyway. Do a search or two on "partial mock" and see what folks have to say about it.

支持部分模拟的最简单方法是使用其他模拟库,例如 Mocha .只需将gem "mocha"添加到您的Gemfile中,就可以了.

The easiest way to support partial mocks is to use a different mocking library like Mocha. Just add gem "mocha" to your Gemfile and you should be good to go.

describe Post do
  before do
    @post = FactoryGirl.build(:post)
  end

  describe "when saving" do
    it "calls the create_slug method before validation" do
      @post.expects(:create_slug).returns(true)
      @post.save
    end
  end
end

但是,如果您真的想使用Minitest :: Mock,有一种方法可以使它起作用.它需要一个新的模拟对象,并使用ruby重新定义create_slug方法.哦,还有全局变量.

But if you really want to use Minitest::Mock there is a way to make it work. It requires a new mock object and using ruby to redefine the create_slug method. Oh, and global variables.

describe Post do
  before do
    @post = FactoryGirl.build(:post)
  end

  describe "when saving" do
    it "calls the create_slug method before validation" do
      $create_slug_mock = Minitest::Mock.new
      $create_slug_mock.expect :create_slug, true

      def @post.create_slug
        $create_slug_mock.create_slug
      end
      @post.save

      $create_slug_mock.verify
    end
  end
end

哇.太丑了看起来像是疏忽吧?为什么Minitest会使部分模拟变得如此困难和丑陋?这实际上是另一个问题的征兆.问题不是如何使用部分模拟?",而是问题如何测试代码的预期行为?"这些测试正在检查实现.如果您重命名了create_slug方法怎么办?或者,如果您将创建段的机制从回调更改为其他东西,该怎么办?这也需要更改此测试.

Wow. That's ugly. Looks like an oversight, right? Why would Minitest make partial mocks so difficult and ugly? This is actually a symptom of a different problem. The question isn't "How do I use partial mocks?", the question is "How do I test the expected behavior of my code?" These tests are checking the implementation. What if you renamed the create_slug method? Or what if you changed the mechanism that created a slug from a callback to something else? That would require that this test change as well.

相反,如果您的测试仅检查了预期的行为,该怎么办?然后,您可以重构代码并更改实现,而无需破坏测试.那会是什么样?

Instead, what if instead your tests only checked the expected behavior? Then you could refactor your code and change your implementation all without breaking the test. What would that look like?

describe Post do
  before do
    @post = FactoryGirl.build(:post)
  end

  describe "when saving" do
    it "creates a slug" do
      @post.slug.must_be :nil?
      @post.save
      @post.slug.wont_be :nil?
    end
  end
end

现在,我们可以自由更改实现,而无需更改测试.这些测试涵盖了预期的行为,因此我们可以重构和清理代码而不会破坏所说的行为.人们问为什么Minitest不支持部分模拟.这就是为什么.您很少需要它们.

Now we are free to change the implementation without changing the tests. The tests cover the expected behavior, so we can refactor and clean the code without breaking said behavior. Folks ask why Minitest doesn't support partial mocks. This is why. You very rarely need them.

这篇关于使用MiniTest检查模型上的方法调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆