How to mock persisting and Entity with Mockito and jUnit

18,986

Solution 1

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

Solution 2

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.

Solution 3

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));
Share:
18,986
Patrick
Author by

Patrick

Updated on June 09, 2022

Comments

  • Patrick
    Patrick over 1 year

    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

  • Dawood ibn Kareem
    Dawood ibn Kareem almost 9 years
    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
  • JB Nizet
    JB Nizet almost 9 years
    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).
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 9 years
    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.
  • Patrick
    Patrick almost 9 years
    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.
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 9 years
    @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.
  • Patrick
    Patrick almost 9 years
    The idea is indeed the same but I prefer this method for it's reusability and for better readability in the test-method itself.
  • Brice
    Brice almost 9 years
    not a big deal, but for custom answer I would create static factory method that return the answer.
  • Brice
    Brice almost 9 years
    Same as JB : not a big deal, but for custom answer I would create static factory method that return the answer.
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 9 years
    @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.
  • Brice
    Brice almost 9 years
    ;) I know but I'm on a Phone so I keep stuff simple.
  • Villat
    Villat over 4 years
    Shouldn't you use when(em).persist(isA(Article.class)) instead?
  • Dawood ibn Kareem
    Dawood ibn Kareem over 4 years
    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