6

I'm trying to find a way to test my entity using Mockito;

This is the simple test method:

@Mock
private EntityManager em;

@Test
public void persistArticleWithValidArticleSetsArticleId() {
    Article article = new Article();
    em.persist(article);
    assertThat(article.getId(), is(not(0L)));
}

How do I best mock the behaviour that the EntityManager changes the Id from 0L to i.e. 1L? Possibly with the least obstructions in readability.

Edit: Some extra information; Outside test-scope the EntityManager is produced by an application-container

Mathijs Segers
  • 6,168
  • 9
  • 51
  • 75
Patrick
  • 489
  • 2
  • 8
  • 12
  • Some extra information; Outside test-scope the EntityManager is produced by an application-container (glassfish). – Patrick Nov 15 '14 at 12:44
  • You can simply test your setId() and getId() methods for Article class. I think there is no need to mock EntityManager and tell it to set id to article. This test will be more suitable when unit testing EntityManager itself, when you want to check if id is generated and set to entity you pass to persist. – pomkine Nov 15 '14 at 13:00
  • 4
    It's not the best case to use mocking library. Take a closer look to your test - what you're testing here is checking if mocking library works, instead of testing your code. Mocks are useful if you need to mock/stub a behavior of internal component of your class under test and you know how this component behaves in particular situations. – Szymon Stepniak Nov 15 '14 at 19:55

3 Answers3

10

You could use a Mockito Answer for this.

doAnswer(new Answer<Object>(){
     @Override
     public Object answer(InvocationOnMock invocation){
        Article article = (Article) invocation.getArguments()[0];
        article.setId(1L);
        return null;
     }
  }).when(em).persist(any(Article.class));

This tells Mockito that when the persist method is called, the first argument should have its setId method invoked.

But if you do this, I don't understand what the purpose of the test would be. You'd really just be testing that the Mockito Answer mechanism works, not that the code of Article or of EntityManager works correctly.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • More or less. I was interested to see that you stored the new id in a field of the `Answer` object. I wouldn't have thought of doing that, unless I wanted to reuse the `Answer` in a few places. But why did you delete yours? I think it's different enough from mine that it's worthwhile to have both here. @JBNizet – Dawood ibn Kareem Nov 15 '14 at 12:54
  • I deleted it because I was basically the same as yours, but came later. I undeleted it since you think it adds something. In that specific case, storing the id is useless. In fact I borrowed code that I'm actually using where the Answer class is indeed in a top-level class, and can be used for any kind of entity, making it reusable (and reused). – JB Nizet Nov 15 '14 at 12:57
  • Thanks for this answer. The reason for this test is more practise-related. I am looking for a way to mock a void-method which runs lines of code when called; For future reference. – Patrick Nov 15 '14 at 13:03
  • 2
    @Patrick - then I recommend you study the Mockito docs that relate to the `Answer` class. This is quite a rich area of the Mockito API, and Mockito has many built-in methods for creating `Answer` objects for various commonly used operations. – Dawood ibn Kareem Nov 15 '14 at 13:05
  • Same as JB : not a big deal, but for custom answer I would create static factory method that return the answer. – bric3 Nov 16 '14 at 18:18
  • 1
    @Brice Maybe you could post that as an answer, with a code snippet, just for visibility reasons, instead of burying it in the comments under my and JB's answers. – Dawood ibn Kareem Nov 16 '14 at 18:49
  • ;) I know but I'm on a Phone so I keep stuff simple. – bric3 Nov 16 '14 at 23:25
  • Shouldn't you use `when(em).persist(isA(Article.class))` instead? – Villat May 15 '19 at 21:04
  • Not really, it makes absolutely no difference, unless OP is testing a method that persists a whole lot of entities of different classes. If that were the case, he'd have mentioned it in the question. @Villat – Dawood ibn Kareem May 15 '19 at 21:24
7
public class AssignIdToArticleAnswer implements Answer<Void> {

    private final Long id;

    public AssignIdToArticleAnswer(Long id) {
        this.id = id;
    }

    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Article article = (Article) invocation.getArguments()[0];
        article.setId(id);
        return null;
    }
}

And then

doAnswer(new AssignIdToArticleAnswer(1L)).when(em).persist(any(Article.class));
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • It's worth noting that with this solution, you can make `AssignIdToArticleAnswer` an inner class of your test class, then use the same `doAnswer` call in several of your test methods. You can even pass in different ids, if it suits you to do so. This makes this solution rather more versatile than my solution, if you're doing anything more than a one-off test. +1. – Dawood ibn Kareem Nov 15 '14 at 13:03
  • The idea is indeed the same but I prefer this method for it's reusability and for better readability in the test-method itself. – Patrick Nov 15 '14 at 13:19
  • not a big deal, but for custom answer I would create static factory method that return the answer. – bric3 Nov 16 '14 at 18:17
4

similar answer as above, but with lambdas

   doAnswer((InvocationOnMock invocation) -> {
        Article article = (Article) invocation.getArguments()[0];
        article.setId(1L);
        return null;
    }).when(em).persist(any(Article.class));
gmode
  • 3,601
  • 4
  • 31
  • 39