Search code examples
javaspringjpamockitoentitylisteners

How to mock a EntityListener function?


I'm trying to mock one function in an EntityListener, so the real implementation is not called in my test. The code looks like the following:

@EntityListeners(myEntityListener.class)
@Entity
public class myEntity {
...
}

public class myEntityListener {
    
    public String doThis() {
         // code i want to skip/mock
         return expensiveToCompute;
    }
    
    @PrePersist
    public void myListener(myEntity e) {
         if (complexConditionToTest) e.setSomething(doThis());
    }
}

I would like to mock doThis(), but run the actual myListener() function so I can test that the complex conditioning is correct.

I tried to test using Mockito, with the following code:

public class MyEntityListenerTest {

    @Autowired
    myEntityRepository repo;
    
    @MockBean
    myEntityListener entityListener;
    
    @Test
    public void myListenerTest() throws Exception {
        String expected = "fake-text";
        Mockito.when(entityListener.doThis()).thenReturn(expected);
        
        myEntity e = new myEntity();
        myEntity stored = repo.save(e);
        assertThat(stored.getSomething()).isEqualTo(expected);
    }
}

The myEntity constructor and doThis call both have more params, removed for simplicity in the example code.

I expected that this would mock the doThis function, but it does not appear to be mocked and the actual implemention is called instead. There are no error messages.

I am guessing that MockBean is not finding an existing myEntityListener bean and instead is creating a new one (which goes unused), but I am not sure how to make the test find the correct myEntityListener.


Solution

  • I couldn't get mockito to work, so I ended up creating a static field I could change instead:

    @EntityListeners(MyEntityListener.class)
    @Entity
    public class myEntity {
    ...
    }
    
    public class MyEntityListener {
        public static final testing = false;
    
        public String doThis() {
             if (testing) return "fake-text";
             // code i want to skip/mock
             return expensiveToCompute;
        }
        
        @PrePersist
        public void myListener(myEntity e) {
             if (complexConditionToTest) e.setSomething(doThis());
        }
    }
    

    This makes the test look like:

    public class MyEntityListenerTest {
    
        @Autowired
        myEntityRepository repo;
    
        @Before
        public final void setup() {
            MyEntityListener.testing = true;
        }
        
        @Test
        public void myListenerTest() throws Exception {
            String expected = "fake-text";
            myEntity e = new myEntity();
            myEntity stored = repo.save(e);
            assertThat(stored.getSomething()).isEqualTo(expected);
        }
    }
    

    If you need the expected text to change you could probably use a string property instead of a boolean, but this was fine for my use case.