Search code examples
javaunit-testingstaticjrubymocha.js

How to Mock Static Java methods with JRuby and Mocha?


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!


Solution

  • 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)