0

I have created a bean with method that I want to test. Unfortunately it's a bean with a PostConstruct annotation in it. I don't want to call the PostConstruct method. How can I do this?

I've tried 2 different ways (as shown in the example below) but none working; init() still gets called.

Can someone please give me a detailed example of how to do this?

DirBean.java

@Singleton
@Startup
public class DirBean implements TimedObject {

  @Resource
  protected TimerService timer;

  @PostConstruct
  public void init() {
    // some code I don't want to run
  }

  public void methodIwantToTest() {
     // test this code
  }
}

MyBeanTest.java

public class MyBeanTest {

    @Tested
    DirBean tested;

    @Before
    public void recordExpectationsForPostConstruct() {
        new Expectations(tested) {
            {
                invoke(tested, "init");
            }
        };
    }

    @Test
    public void testMyDirBeanCall() {
        new MockUp<DirBean>() {
            @Mock
            void init() {
            }
        };  
        tested.methodIwantToTest();
    }
}

MyBeanTest2.java (WORKS)

public class MyBeanTest2 {

    @Tested
    DirBean tested;

    @Before
    public void recordExpectationsForPostConstruct() {
       new MockUp<DirBean>() {
            @Mock
            void init() {}
       };
    }

    @Test
    public void testMyDirBeanCall() {
        tested.methodIwantToTest();
    }
}

MyBeanTest3.java (WORKS)

public class MyBeanTest3 {

    DirBean dirBean = null;

    @Mock
    SubBean1 mockSubBean1;

    @Before
    public void setupDependenciesManually() {
        dirBean = new DirBean();
        dirBean.subBean1 = mockSubBean1;
    }

    @Test
    public void testMyDirBeanCall() {
        dirBean.methodIwantToTest();
    }
}

MyBeanTest4.java (FAILS with NullPointerException on invoke())

public class MyBeanTest4 {

    @Tested
    DirBean tested;

    @Before
    public void recordExpectationsForCallsInsideInit() {
        new Expectations(tested) {
        {
            Deencapsulation.invoke(tested, "methodCalledfromInit", anyInt);
        }
        };
    }

    @Test
    public void testMyDirBeanCall() {
        tested.methodIwantToTest();
    }
}
Miyagi
  • 154
  • 2
  • 17
  • 1
    I think you're going about it the wrong way. The `init()` method is an essential part of the class under test, it shouldn't be mocked away. Instead, mock whatever other component it calls, if needed. – Rogério Oct 18 '16 at 13:41
  • Possibly, but the problem is that the init() is called before the test. So if I try to mock out the private calls made inside init(), it will give me a null-pointer exception on tested-variable. Maybe I can't use @Tested in this case? – Miyagi Oct 18 '16 at 14:10
  • If `init()` calls other methods on the same tested class (`private` or not) they shouldn't be mocked either. The only methods that "should" be mocked are those belonging to classes *other* than the one being tested. It would be easier to help if I knew [what the actual problem is](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Rogério Oct 18 '16 at 14:37
  • The init function creates a timer, that will wait x minutes and then call another function and finally creates a new timer. So running it would not be useful in a unit test and therefor want to mock it out completely. Hope I explained it well enough.. ;-) – Miyagi Oct 18 '16 at 15:01
  • 1
    The test will need to have an `@Injectable TimerService timer`, otherwise `@Tested DirBean` fails (since `@Resource` indicates a mandatory dependency). So, assuming that the timer is created from `init()` by using the mock `timer`, what's the problem? – Rogério Oct 18 '16 at 15:49
  • Good point. :-) Init() also calls some System and File methods, which I don't want to do, but that is a whole different issue. – Miyagi Oct 19 '16 at 19:11

1 Answers1

3

Move definition of MockUp type to @Before method:

public class MyBeanTest {

    @Tested
    DirBean tested;

    @Before
    public void recordExpectationsForPostConstruct() {
        new MockUp<DirBean>() {
            @Mock
            void init() {
            }
        }; 
    }

    @Test
    public void testMyDirBeanCall() {
        tested.methodIwantToTest();
    }
}
kaos
  • 1,598
  • 11
  • 15
  • Thanks for answer. It worked but got warning: Warning: Invalid mock-up for internal class DirBean at MyBeanTest$1. (MyBeanTest.java). However, it worked. It seems to be a newly added warning. The other way to do it was: initialize the DirBean as a regular variable (without the @Tested) and add then initialize the injected beans manually. Such as: – Miyagi Oct 17 '16 at 15:48
  • '@Before public void beforeTest() { dirBean = new DirBean(); dirBean.subBean = mockSubBean; etc etc }' – Miyagi Oct 17 '16 at 15:49
  • Hmm i do not see this warning, I'm using version 1.25 of JMockit. – kaos Oct 18 '16 at 09:39