Подигравка на EntityManager

Получавам NPE, докато се подигравам на 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
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);
    }
}

Докато отстраняването на грешки em не е null (също други аргументи REPLICATION_DOMAIN, SOURCE_NODE_INDEX, NODE_CHANGE_NUMDER не са null) в клас Entity, докато em.createNamedQuery("NodeChangeDelta.findIdByNaturalKey", String.class) е null.


person Arasu    schedule 06.04.2015    source източник
comment
Очаквате ли вашият макет да изпълни действителна заявка? Това няма да работи. Той няма познания за вашия източник на данни, контекст на постоянство, именувани заявки и т.н.   -  person Robby Cornelissen    schedule 06.04.2015


Отговори (2)


В wiki на mockito: Не се подигравайте на типове, които не притежавате!

Това не е твърда граница, но преминаването й може да има последствия! (най-вероятно ще стане.)

  1. Представете си код, който осмива библиотека на трета страна. След конкретен ъпгрейд на трета библиотека логиката може да се промени малко, но тестовият пакет ще се изпълни добре, защото е подиграван. Така че по-късно, мислейки, че всичко е готово, стената за изграждане все пак е зелена, софтуерът е внедрен и... Бум
  2. Това може да е знак, че текущият дизайн не е достатъчно отделен от тази библиотека на трета страна.
  3. Също така друг проблем е, че библиотеката на трета страна може да е сложна и да изисква много подигравки, за да работи дори правилно. Това води до прекалено специфични тестове и сложни приспособления, което само по себе си компрометира целта за компактност и четливост. Или към тестове, които не покриват достатъчно кода, поради сложността да се подиграват с външната система.

Вместо това, най-често срещаният начин е да се създадат обвивки около външната библиотека/система, въпреки че човек трябва да е наясно с риска от изтичане на абстракция, където твърде много API на ниско ниво, концепции или изключения излизат извън границите на обвивката. За да проверите интеграцията с библиотеката на трета страна, напишете интеграционни тестове и ги направете възможно най-компактни и четливи.

Подигравателен тип, който нямате контрол, може да се счита за (подигравателен) анти-шаблон. Въпреки че EntityManager е почти стандартен, не трябва да се смята, че няма да има промяна в поведението в предстоящите версии на JDK / JSR (вече се е случвало много пъти в друга част на API, просто погледнете JDK бележки към изданието). Освен това реалните реализации може да имат тънкости в поведението си, които трудно могат да бъдат подигравани, тестовете може да са зелени, но производствените котки са запалени (истинска история).

Мисълта ми е, че ако кодът трябва да се подиграва с тип, който не притежавам, дизайнът трябва да се промени възможно, така че аз, моите колеги или бъдещите поддържащи този код да не попаднем в тези капани.

Също така wiki връзката към други записи в блогове, описващи проблемите, които са имали, когато са се опитвали да се подиграват с текст, който не са имали контрол.

Вместо това наистина съветвам всички да не използват макет, когато тестват интеграция с друга система. Вярвам, че за неща с бази данни, Arquillian е нещото, което трябва да се направи, проектът изглежда доста активен.


Адаптирано от моя отговор: https://stackoverflow.com/a/28698223/48136

person Brice    schedule 06.04.2015

В Mockito всяко извикване на метод на макет, който не е изрично конфигуриран, винаги връща null. Следователно в findIdByNaturalKey, em.createNamedQuery връща null и така NPE на setParameter. Трябва да го конфигурирате за RETURN_MOCKS.

Освен това не съм сигурен дали @InjectMocks поддържа @PersistenceContext. Ако не, тогава em вероятно е нула. Ако се случи, моля, уведомете ме и горното е ваш проблем.

person John B    schedule 06.04.2015
comment
@InjectMocks не е наясно с spring/jee, той просто се опитва да намери съвпадащ тип. Това не е истинска рамка за инжектиране на зависимости. - person Brice; 06.04.2015