Тестовый пример JUnit: java.lang.NullPointerException - PullRequest
0 голосов
/ 02 мая 2018

Я пытаюсь написать JUnit контрольный пример для Repository. Я добавил H2 в зависимости от базы данных памяти и настройки конфигурации для базы данных h2. Но я получаю null pointer exception. Может кто-нибудь сказать, пожалуйста, что я делаю не так в коде?

Отдел

@Entity
@Table(name = "department")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Department implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "department_seq_generator")
    @SequenceGenerator(name = "department_seq_generator", sequenceName = "department_seq")

    @Column(name = "ndept_id")
    public Integer nDeptId;

    @Column(name = "sdept_name")
    public String sDeptName;

    @Column(name = "ninst_id")
    public Integer nInstId;

    @Column(name = "bis_locked")
    public Boolean bIsLocked;

    @Column(name = "sclient_dept_id")
    public String sClientDeptId;

    @Column(name = "nsurvey_method_id")
    public Integer nSurveyMethodId;

    @Column(name = "bis_jointuse")
    public Boolean bIsJointuse;

    @Column(name = "ntemp_dept_id")
    public Integer nTempDeptId;

    @Column(name = "balternate_jointuse_percentage")
    public Boolean bAlternateJointusePercentage;

    @Column(name = "ndiv_id")
    public Integer nDivId;

    // Getter and Setter

DepaertmentRepository

@Repository
    public interface DepaertmentRepository extends JpaRepository<Department, Integer> {

        Department findByNDeptId(Integer nDeptId);
    }

DepartmentRepositoryTest

@RunWith(SpringRunner.class)
@DataJpaTest
public class DepartmentRepositoryTest { 

    @Autowired
    private static DepaertmentRepository depRepo; 

    @Autowired
    public TestEntityManager em;        

@Test
public void TestFindById() {

    Department dep = new Department();
    dep.setnDeptId(1);

    System.out.println(dep.getnDeptId());// here i am getting 1

    Department saveInDB = em.merge(dep);        

    System.out.println(saveInDB.getnDeptId());// here i am getting 50

    Department getFromDB = depRepo.findByNDeptId(saveInDB.getnDeptId());

    System.out.println(getFromDB.getnDeptId());// here i am getting 50

    assertThat(getFromDB).isEqualTo(saveInDB);
}       
}

Трассировка стека для PersistenceException

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.spacestudy.model.Department
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1152)
    at org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager.persist(TestEntityManager.java:93)
    at com.spacestudy.DepartmentRepositoryTest.TestFindById(DepartmentRepositoryTest.java:36)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.spacestudy.model.Department
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146)
    ... 31 more

Использование вышеприведенного кода Тестовый пример успешно выполняется без исключения нулевого указателя. Но когда я ставлю контрольную точку в каждой строке, я наблюдаю, что я сохраняю nDeptId как 1 после слияния с БД здесь saveInDB.getnDeptId() Я получаю 50. Я не поняла, почему 50, а не 1;

1 Ответ

0 голосов
/ 02 мая 2018

Это может быть полезно!

Проблема здесь: Department found = depRepo.findByNDeptId(1); Вы ожидаете, что данные будут возвращены вместо нуля.

По умолчанию тесты, помеченные @DataJpaTest, будут использовать встроенную базу данных в памяти (заменяя любой явный или обычно автоматически настраиваемый источник данных).

Итак, исходя из того, что вы указали в своем вопросе:

  • Проверьте, есть ли у вас ожидаемые тестовые данные. Вам необходимо иметь эту запись с ID = 1 в вашей базе данных в памяти или в используемой вами БД.
  • Если у вас нет необходимости сначала подготовить некоторые тестовые данные (например, в своем классе теста добавьте метод @BeforeClass, где вы можете вставить некоторые тестовые данные перед запуском теста)
  • Может быть, когда вы создаете свои тестовые данные с помощью entityManager (эта строка entityManager.merge(dep);), он сохраняет их в другой БД? Не тот, который вы читаете после? В любом случае, лучше создать тест, прежде чем запускать его.

1020 * Е.Г. *

@BeforeClass
public static void init() {
    // you could try instead of this to use your Repository to create test data
    Department dep = new Department();
    dep.setnDeptId(1);
    // entityManager.merge(dep);
    yourRepo.save(dep);    
}

Обновление:

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "department_seq_generator")
    @SequenceGenerator(name = "department_seq_generator", sequenceName = "department_seq")

    @Column(name = "ndept_id")
    public Integer nDeptId;

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

В основном, как это работает: когда вы сохраняете новую запись, вызывается что-то вроде sequence get me next id, и вы получаете ID.

Вот почему, даже если вы установите что-то для идентификатора (, что не следует делать ), вы получите совершенно другое число!

Итак, вот как вы можете изменить свой тест:

@Test
public void TestFindById() {

    Department dep = new Department();
    // you can set some fields here but not ID

    // this is saved entity, it means it has an ID assigned by the database
    Department saveInDB = em.merge(dep);        

    // that is what you need
    final Integer newRecordID = getFromDB.getnDeptId();

    // test your repository or what you need
    Department getFromDB = depRepo.findByNDeptId(newRecordID);


    // all asserts that you need
    assertThat(getFromDB).isEqualTo(saveInDB);
} 
...