如何使用 JRuby 和 Mocha 模拟静态 Java 方法?
我的目标是使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我意识到这个问题很久以前就被问过,但我遇到了一个非常相似的问题并最终得到了解决。我认为问题在于您对 any_instance 的使用...
至少在我的场景中,解决方案是直接在包含静态方法的类上调用存根:
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:
我自己没有使用过这个,但是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.