Mocking EJB injection in tests

2019-02-17 18:43发布

问题:

Whenever I want to test a class which uses resource injection I end up including a constructor that will only be used within the test:

public class A {

    @EJB
    B b;

    // Used in tests to inject EJB mock
    protected A(B b) {
        this.b = b;
    }

    public A() {}

    // Method that I wish to test
    public void foo() {
        b.bar();
    }

}

Is there another way of mocking resource injection or this is the correct pattern to follow?

回答1:

you could use easy gloss to that effect, it mocks the EJBs injection system.

another way is to set the field using reflexion in your tests, I sometime use something like this :

public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) throws Exception {
    Field setId = instanceFieldClass.getDeclaredField(fieldName);
    setId.setAccessible(true);
    setId.set(instance, fieldValue);
}


回答2:

Eliocs,

If type B where an interface then you wouldn't "just" bo doing it for test-cases; you'd be allowing for any alternative implementations of "B's behaviour", even if the need for it/them hasn't been dreamed-up yet.

Yeah, basically that's the only pattern to follow (AFAIK)... so (rightly or wrongly) you may as well make the best of it ;-)

Cheers. Keith.



回答3:

It's certainly one way to do it, although I'd rely on package access; don't provide a constructor injection point, but simply have your test in the same package as the bean being tested. That way, your test can just access the value directly (assuming it's not private):

@Test
public void EJBInjectionTest() {
   A a=new A();
   a.b=new B() {
       // mock functionality here, of course...
   };
   assertNotNull(a.b);
}