如何使用 JRuby 和 Mocha 模拟静态 Java 方法?

发布于 2024-10-05 17:24:22 字数 2310 浏览 0 评论 0原文

我的目标是使用 JRuby 和 Mocha 对充满静态实用方法的遗留 Java 代码进行单元测试。这可能吗?

我正在尝试应用 JMockit 中可用的类似技术;利用代理动态改变测试行为的框架。纯粹主义者可能会建议重构静态方法,但目前这是不可能的。

我将两个单元测试放在一起:

测试 #1 - Ruby Mocking - 我的控制。
测试 #2 - Java 模拟 - 看看我是否可以在 Java 中完成相同的任务。

对于这两个测试,我正在替换“getTax”方法。

代码如下:

测试 1

require 'rubygems'
require 'dust'
require 'mocha'

unit_tests do

    # Test 1 - Stub out JRuby secondary class and override the "getTax" method
    # This is my "control" - I'm overriding the tax multiplier from 1.15 to 1.18.
    # It works =)
    test "RubyMocking" do
        # System Under Test
        class RInvoice 
            def initialize
                @util = RInvoiceUtil.new
            end
            def calculate
                @util.getTax * 10.0
            end
        end

        # Dependency
        class RInvoiceUtil 
            # we'll stub out this method and change the tax rate
            def getTax
                1.15
            end
        end

        invoice = RInvoice.new      
        # change the tax rate
        RInvoiceUtil.any_instance.stubs(:getTax).returns(1.18)      
        assert_equal(invoice.calculate.to_s, "11.8")
    end
end

测试 2

include Java

require 'rubygems'
require 'dust'
require 'mocha'
require 'invoice.jar'
Invoice = Java::example.Invoice
InvoiceUtil = Java::example.InvoiceUtil

unit_tests do

# Test 2 - Stub out Java class InvoiceUtil and it's *static* getTax method.
# This can be achieved via JMockit, but is it possible in Mocha?

  test "JavaMocking" do
    invoice = Invoice.new       
    # this does not work because the ruby objects are only 
    # proxies to the java objects?
    InvoiceUtil.any_instance.stubs(:getTax).returns(1.18)       
    assert_equal(invoice.calculate, 11.8)   
  end
end

测试 2 失败并显示: <11.5>预期结果是<11.8>。好吧,所以我不能这么做。唔。这不起作用的原因是 ruby​​ 对象只是 java 对象的代理吗?

Java 源代码

package example;
public class Invoice {
    public double calculate() {
        return InvoiceUtil.getTax() * 10.0;
    }
}

public class InvoiceUtil {
    public static double getTax() {
        return 1.15;
    }
}

总结

我想做的就是将静态方法模拟与 JRuby 结合起来,以利用 (1) 简单的脚本编写和 (2) 灵活的测试隔离。

预先感谢您的回复!

My goal is to unit test legacy Java code, riddled with static utility methods, using JRuby and Mocha. Is this possible?

I am trying to apply similar techniques that are available in JMockit; a framework leveraging proxies to change test behavior dynamically. Purists may suggest refactoring out the static methods, but at this point, it's just not possible.

I put together two unit tests:

Test #1 - Ruby Mocking - my control.
Test #2 - Java Mocking - to see if I can accomplish the same in Java.

For both tests, I'm replacing the "getTax" method.

Here is the code:

Test 1

require 'rubygems'
require 'dust'
require 'mocha'

unit_tests do

    # Test 1 - Stub out JRuby secondary class and override the "getTax" method
    # This is my "control" - I'm overriding the tax multiplier from 1.15 to 1.18.
    # It works =)
    test "RubyMocking" do
        # System Under Test
        class RInvoice 
            def initialize
                @util = RInvoiceUtil.new
            end
            def calculate
                @util.getTax * 10.0
            end
        end

        # Dependency
        class RInvoiceUtil 
            # we'll stub out this method and change the tax rate
            def getTax
                1.15
            end
        end

        invoice = RInvoice.new      
        # change the tax rate
        RInvoiceUtil.any_instance.stubs(:getTax).returns(1.18)      
        assert_equal(invoice.calculate.to_s, "11.8")
    end
end

Test 2

include Java

require 'rubygems'
require 'dust'
require 'mocha'
require 'invoice.jar'
Invoice = Java::example.Invoice
InvoiceUtil = Java::example.InvoiceUtil

unit_tests do

# Test 2 - Stub out Java class InvoiceUtil and it's *static* getTax method.
# This can be achieved via JMockit, but is it possible in Mocha?

  test "JavaMocking" do
    invoice = Invoice.new       
    # this does not work because the ruby objects are only 
    # proxies to the java objects?
    InvoiceUtil.any_instance.stubs(:getTax).returns(1.18)       
    assert_equal(invoice.calculate, 11.8)   
  end
end

Test 2 fails with: <11.5> expected but was <11.8>. Ok, so I can't do that. Hmm. Is the reason this does not work because the ruby objects are only proxies to the java objects?

Java Source

package example;
public class Invoice {
    public double calculate() {
        return InvoiceUtil.getTax() * 10.0;
    }
}

public class InvoiceUtil {
    public static double getTax() {
        return 1.15;
    }
}

To Sum Up

All I want to do is combine static method mocking with JRuby to leverage (1) easy scripting with (2) flexibile test isolation.

Thanks in advance for your responses!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

人生戏 2024-10-12 17:24:22

我意识到这个问题很久以前就被问过,但我遇到了一个非常相似的问题并最终得到了解决。我认为问题在于您对 any_instance 的使用...

至少在我的场景中,解决方案是直接在包含静态方法的类上调用存根:

InvoiceUtil.stubs(:getTax).returns(1.18)

I realize this question was asked a long time ago, but I came along a very similar problem and finally got it working. I think the problem is in your usage of any_instance...

At least in my scenario the solution was to call stubs directly on the class containing the static method:

InvoiceUtil.stubs(:getTax).returns(1.18)
要走就滚别墨迹 2024-10-12 17:24:22

我自己没有使用过这个,但是Ola Bini发布了JtestR 不久前,这可能就是您正在寻找的。看起来他已经解决了您遇到的any_instance问题多于。我不知道 JtestR 的最新情况如何,但是查看 Ola 的 GitHub 帐户,有一些最近的内容提交,所以你可能会很幸运。我希望这有帮助。

I haven't used this myself, but Ola Bini released JtestR a while ago which might be what you're looking for. It looks like he has addressed the any_instance problem you are seeing above. I have no idea how up-to-date JtestR is, but looking at Ola's GitHub account there are some recent commits, so you could be in luck. I hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文