2015-04-06 1 views
1

Я получаю NPE, а насмешливый EntityManager, ниже мой код,Mocking EntityManager

@Stateless 
public class NodeChangeDeltaQueryBean implements NodeChangeDeltaQueryLocal { 

    @PersistenceContext 
    private EntityManager em; 
    @Override 
    public String findIdByNaturalKey(final String replicationDomain, final int sourceNodeIndex, 
            final int nodeChangeNumber) { 
     List<String> result = 
      NodeChangeDelta.findIdByNaturalKey(this.em, replicationDomain, sourceNodeIndex, 
       nodeChangeNumber).getResultList(); 
     return result.isEmpty() ? null : result.get(0); 
    } 
} 

Мой Entity Класс

@Entity 
public class NodeChangeDelta implements Serializable, Cloneable, GeneratedEntity, KeyedEntity<String> { 

public static TypedQuery<String> findIdByNaturalKey(final EntityManager em, final String replicationDomain, final int sourceNodeIndex, final int nodeChangeNumber) { 
     return em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey", String.class) 
      .setParameter("replicationDomain", replicationDomain) 
      .setParameter("sourceNodeIndex", sourceNodeIndex) 
      .setParameter("nodeChangeNumber", nodeChangeNumber); 
    } 
} 

Мой тест Класс

@RunWith(MockitoJUnitRunner.class) 
public class NodeChangeDeltaQueryBeanTest { 

    @InjectMocks 
    NodeChangeDeltaQueryBean nodeChangeDeltaQueryBean; 

    @Mock 
    EntityManager em; 

@Test 
    public void testFindIdByNaturalKey() { 
     this.addNodeChangeDelta(); 
     this.nodeChangeDeltaQueryBean.findIdByNaturalKey(this.REPLICATION_DOMAIN, 
      this.SOURCE_NODE_INDEX, this.NODE_CHANGE_NUMDER); 
    } 
} 

При отладке им, не null (также другие аргументы REPLICATION_DOMAIN, SOURCE_NODE_INDEX, NODE_CHANGE_NUMDER не равно null) в Entit y, тогда как em.createNamedQuery ("NodeChangeDelta.findIdByNaturalKey", String.class) является нулевым.

+0

Ожидаете ли вы ваш макет выполнить фактический запрос? Это не сработает. Он не знает вашего источника данных, контекста персистентности, именованных запросов и т. Д. –

ответ

0

В Mockito любой вызов метода для макета, который явно не настроен, всегда возвращает null. Поэтому в findIdByNaturalKey, em.createNamedQuery возвращается null и поэтому NPE на setParameter. Вам необходимо настроить его на RETURN_MOCKS.

Кроме того, я не уверен, поддерживает ли @InjectMocks@PersistenceContext. Если это не так, то em, вероятно, null. Если да, дайте мне знать, и это ваша проблема.

+0

'@ InjectMocks' не знает Spring/Jee, он просто пытается найти подходящий тип. Это не настоящая структура внедрения инъекций. – Brice

1

На Mockito вики: Don't mock types you don't own !

Это не жесткая линия, но пересекая эту линию, может иметь последствия! (это, скорее всего, будет.)

  1. Представьте код, издевающийся над третьей стороной lib. После определенного обновления третьей библиотеки логика может немного измениться, но набор тестов будет выполняться просто отлично, потому что это насмехается. Поэтому позже, думая, что все хорошо, строительная стена в конечном счете зеленая, программное обеспечение развернуто и ... Boom
  2. Это может быть признак того, что текущий дизайн не отделился от этой третьей партийной библиотеки.
  3. Еще одна проблема заключается в том, что сторонняя библиотека может быть сложной и требует много макетов даже для правильной работы. Это приводит к чрезмерно указанным испытаниям и сложным светильникам, что само по себе компрометирует компактный и читаемый цель . Или к тестам, которые недостаточно покрывают код, из-за сложности издеваться над внешней системой.

Вместо этого наиболее распространенным способом является создание оберток вокруг внешней библиотеки lib/system, хотя следует помнить о риске утечки абстракции, где слишком много API низкого уровня, понятия или исключения выходит за пределы границы обертки. Чтобы проверить интеграцию с сторонней библиотекой, запишите тесты интеграции и сделайте их как можно более компактными и читаемыми.

Mock типа, что вы не имеете контроля можно считать (насмешливый) антишаблоном. В то время как EntityManager в значительной степени стандарт, не следует учитывать, что в предстоящих выпусках JDK/JSR не будет изменений поведения (это уже было много раз в другой части API, просто посмотрите на заметки о выпуске JDK).Кроме того, реальные реализации могут иметь тонкости в их поведении, которые вряд ли могут быть издевательствами, тесты могут быть зелеными, но производственные коты находятся под огнем (истинная история).

Я хочу сказать, что если код нуждается в том, чтобы издеваться над типом, который у меня нет, дизайн должен изменить asap, так что я, мои коллеги или будущие сторонники этого кода не попадут в эти ловушки.

Также wiki ссылается на другие записи в блогах, описывая проблемы, которые у них были, когда они пытались имитировать тип, которым они не обладали контролем.

Вместо этого я действительно советую всем не использовать макет при тестировании интеграции с другой системой. Я считаю, что для базы данных, Arquillian - это то, что нужно, проект выглядит довольно активным.


Взято из моего ответа: https://stackoverflow.com/a/28698223/48136