如何使用Mocha进行模拟实际上允许您测试函数中的逻辑?

时间:2013-01-06 02:45:18

标签: ruby-on-rails ruby unit-testing mocha

我开始学习如何模仿,因为使用Factory Girl对于1000多个测试的项目来说并不是很实用。我无法在每次测试中使用数据库,特别是如果我希望进行任何类型的自动持续集成。

我的测试:

    it "should return an URL with the desired security protocol" do
        p = Proposal.new
        p.expects(:status).returns(Proposal::PUBLISHED) #this should be invoked by public_url?
        p.expects(:public_url).returns("https://something")
        p.expects(:public_url).with(true).returns("https://something")
        p.expects(:public_url).with(false).returns("http://something")
        assert p.public_url.index("https") != nil
        assert p.public_url(true).index("https") != nil
        assert p.public_url(false).index("https") == nil
    end

上述测试的方法:

def public_url(https = true)
    url = ""
    if self.published?
        # attepmt to find sluggable id
        id = sluggable_id
        url = (https ? "#{ENV['SSL_PROTOCOL']}://" : "http://") + 
            self.account.full_domain + "/view/" + id.to_s
    end

    return url
end 

def published?
    return self.status > UNPUBLISHED
end

但这是我在运行测试时得到的结果:

unsatisfied expectations:
- expected exactly once, not yet invoked: #<Proposal:0x7fbd07e82a30>.status(any_parameters)

public_url的调用不应该调用status()吗?

如果没有,那么如果我必须自己调用p.status,那是不是意味着p.public_url()完全忽略了我所写的逻辑,并严格遵循我在{{1}中定义的内容}}? 这对单元测试有何帮助? 也许我不明白嘲笑的目的。


更新:

根据@ Philip的建议,我改变了我的测试,取消了对任何ActiveRecord恶作剧的需求:

expects

我想现在我的问题是,我如何使用一个夹具(我将其命名为 it "should return an URL with the desired security protocol" do p = Proposal.new p.expects(:id).returns(1) p.expects(:status).returns(Proposal::PUBLISHED) p.expects(:account).returns(Account.new.stubs(:localhost)) assert p.public_url.starts_with("https") assert p.public_url(true).starts_with("https") assert !p.public_url(false).starts_with("https") end ?)来存根帐户。我收到错误:localhost但我的夹具定义如下:

undefined method 'full_domain' for Mocha::Expectation:

我设置了固定装置,以便我可以拥有常用模型的基础知识,以便在我的所有测试中使用。每个测试的标准模型/关系(如果我是手工测试/与工厂女孩进行测试而不进行模拟,则需要: localhost: id: 1 name: My first account full_domain: test.domain.vhost Account(有SubscriptionAccount),SubscriptionPlanSubscriptionPlan(属于User),{{1 (Account),然后是我正在测试的实际对象,它属于AccountProperties上的AccountAccount,有点每次测试都很重要。哈哈


更新2:

搞定了:

User

结果证明,您可以访问Accountit "should return an URL with the desired security protocol" do p = Proposal.new({:status => Proposal::PUBLISHED}) p.expects(:id).returns(1) p.expects(:account).returns(accounts(:localhost)).times(3) assert p.public_url.starts_with?("https") assert p.public_url(true).starts_with?("https") assert !p.public_url(false).starts_with?("https") end 等固定装置。

1 个答案:

答案 0 :(得分:1)

我对它的理解是你的三条p.expects(:public_url)...行正在剔除该方法并返回你告诉它返回的值。所以一旦你完成了这个,你的方法体就永远不会被召唤......存根已经接管了。因此......既然你告诉它也期望打电话给status,那就永远不会发生。

查看您的代码...我认为您想要删除的内容是self.account.full_domain,可能id.to_s在此行中:

url = (https ? "#{ENV['SSL_PROTOCOL']}://" : "http://") + 
            self.account.full_domain + "/view/" + id.to_s

这将跳过任何AR关系的东西,但仍然在你的方法中运用其余的条件。

另外..我会改变你的断言。下面还将匹配一个非安全网址,如“http://https.com/blahblah”,这不是你真正想要的。其他的也可以通过,但也有无效原因。

assert p.public_url(true).index("https") != nil

所以可能是这样的:

assert p.public_url(true).starts_with("https://") true

或者,取结果并使用URI解析它,然后直接测试方案(可能是矫枉过正的想法)