3

我开始学习如何模拟事物,因为对于有 1000 多个测试的项目来说,使用 Factory Girl 并不是很实用。我不能每次测试都访问数据库,特别是如果我希望进行任何类型的自动化持续集成。

我的测试:

    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调用 invokestatus()吗?

如果不是,那么如果我不得不打电话给p.status自己,那是不是p.public_url()完全无视我写的逻辑,并严格遵循我在中定义的内容expects?这对单元测试有什么帮助?也许我不明白嘲笑的目的。


更新:

根据@Philip 的建议,我将我的测试更改为这个,消除了对任何 ActiveRecord 恶作剧的需要:

    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

我设置了固定装置,这样我就可以拥有常用模型的基础知识,以便在我的所有测试中轻松使用。每个测试的标准模型/关系(如果我是手动/与工厂女孩一起进行测试,没有嘲笑,将需要: AccountSubscription(has AccountSubscriptionPlan),,SubscriptionPlanUser属于Account),AccountProperties(has Account),然后是实际的对象我在测试on,属于anAccount和a Useron that Account,每次测试都有点多。哈哈


更新 2:

得到它的工作:

it "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

事实证明,您可以访问诸如accounts或之类的固定装置users

4

1 回答 1

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 关系内容,但仍会在您的方法中执行其余条件。

另外..我会改变你的断言。下面的内容也将匹配非安全 URL,例如“http://https.com/blahblah”,这不是您真正想要的。其他的也可以通过,但也是出于无效的原因。

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

所以也许是这样的:

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

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

于 2013-01-06T02:58:46.370 回答