【问题标题】:Correct configuration to mock Hibernate's sessionFactory.getCurrentSession()正确配置以模拟 Hibernate 的 sessionFactory.getCurrentSession()
【发布时间】:2017-08-16 02:21:49
【问题描述】:

我有以下几点:

@Repository
@Transactional
@HibernateProfile
public class PersonaHibernateRepository implements PersonaRepository {

    private static final Logger logger = LoggerFactory.getLogger(PersonaHibernateRepository.class.getSimpleName());

    private final SessionFactory sessionFactory;

    public PersonaHibernateRepository(SessionFactory sessionFactory){
        logger.info("{} constructor", PersonaHibernateRepository.class.getSimpleName());
        this.sessionFactory = sessionFactory;
    }

    @Override
    public Persona saveOne(Persona persona) {
        String generatedIdentifier = (String) sessionFactory.getCurrentSession().save(persona);
        logger.info("generatedIdentifier: {}", generatedIdentifier);
        return persona;
    }

...

每个crud 方法都有sessionFactory.getCurrentSession()

Mockito下面这句话:

when(sessionFactory.getCurrentSession().save(persona)).thenReturn(persona.getId());

总是抛出java.lang.NullPointerException。我已经确认sessionFactory.getCurrentSession() 是问题的关键。

我已经阅读了以下内容:

因此java.lang.NullPointerException 被删除。

但我总是现在:

org.mockito.exceptions.verification.TooManyActualInvocations: 
sessionFactory.getCurrentSession();
Wanted 1 time:
-> at com.manuel.jordan.repository.hibernate.PersonaHibernateRepositoryTest_.saveOneTest(PersonaHibernateRepositoryTest_.java:76)
But was 2 times. Undesired invocation:
-> at com.manuel.jordan.repository.hibernate.PersonaHibernateRepository.saveOne(PersonaHibernateRepository.java:43)

这两次发生是由于模拟调用和目标调用。

目前我的配置是:

private PersonaHibernateRepository personaHibernateRepository;
private SessionFactory sessionFactory;
private Session session;

...

@Before
public void setup(){
    sessionFactory = mock(SessionFactory.class);
    session = mock(Session.class);
    personaHibernateRepository = new PersonaHibernateRepository(sessionFactory);
    //Removes NullPointerException - 'A'
    when(sessionFactory.getCurrentSession()).thenReturn(session);
}

@Test
public void saveOneTest(){

    //java.lang.NullPointerException removed thanks to 'A'      
    when(sessionFactory.getCurrentSession().save(persona)).thenReturn(persona.getId());

    Persona persona_ = personaHibernateRepository.saveOne(persona);
    assertThat(persona_, is(persona));

    //B
    verify(sessionFactory).getCurrentSession().save(persona);
}

只是玩,如果我改变:

发件人:verify(sessionFactory).getCurrentSession().save(persona);

收件人:verify(sessionFactory, times(2)).getCurrentSession().save(persona);(注意times(2)

verify(sessionFactory, times(2)).getCurrentSession().save(persona); (B) now 再次出现java.lang.NullPointerException

如果在@Before 中将when(sessionFactory.getCurrentSession()).thenReturn(session) 更改为doReturn(session).when(sessionFactory).getCurrentSession(),则会出现同样的异常

什么是正确的配置?

【问题讨论】:

  • verify(sessionFactory).getCurrentSession().save(persona); 应该是verify(sessionFactory.getCurrentSession()).save(persona);

标签: java unit-testing junit mockito


【解决方案1】:

setup() 方法中,当调用sessionFactory.getCurrentSession() 时,您正确地告诉Mockito 返回模拟的session 实例,因此您的断言应该关注session 实例而不是sessionFactory。例如:

@Test
public void saveOneTest(){
    // you have already told Mockito to return this session instance when sessionFactory.getCurrentSession() is 
    // invoked so now your when (and optionally verify) should focus on session rather than on sessionFactory
    when(session.save(persona)).thenReturn(persona.getId());

    Persona persona_ = personaHibernateRepository.saveOne(persona);
    assertThat(persona_, is(persona));

    verify(session).save(persona);
}

【讨论】:

  • 谢谢,您的建议有效,现在有些让我感到困惑,而且我从未在任何教程中看到过这种方法或行为,我认为对于 Mockito 来说,when/thenReturnverify 是强制性的或反映saveOne 方法中使用的相同 代码。 sessionFactory.getCurrentSession().save(persona);。考虑为社区添加一个额外的解释
  • 对于同一个被测方法,不必同时使用when/thenReturn verifyverify 调用允许您断言在您的模拟对象上调用了一个方法,并验证传递给该方法调用的参数。 when/thenReturn 间接允许同样的事情,但有额外的副作用是允许模拟对象参与您的代码流,就好像它是一个真实的对象一样。因此,它们可以用来实现相同的目标,尽管在某些情况下一个优先于另一个的情况也是正确的,但它们必须一起使用是不正确的。
  • 有趣并感谢解释,只是好奇它是否反映在当前的 mockito 文档中。我正在考虑创建一个问题以改进其文档。
  • 只是在同一张图片中,saveOne 方法包含 sessionFactory.getCurrentSession().save(persona) 语句,但在 when/thenReturnverify 调用中,它们直接工作Session 代替。
猜你喜欢
  • 2016-03-07
  • 2013-04-10
  • 2015-03-21
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 2015-03-05
  • 1970-01-01
相关资源
最近更新 更多