0

I am trying to write JUnit test case for Repository. I added H2 in memory database dependency also setup configuration for h2 database. But I am getting null pointer exception. Can any one please tell me what I am doing wrong in code?

Department

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

Stack Trace for 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

Using above code Test case is running successfully without null pointer exception. But when I putted checkpoint at every line I observer that I am saving nDeptId as 1 after merge in DB here saveInDB.getnDeptId() I am getting 50. I didn't understood why its coming 50 not 1;

SpringUser
  • 1,351
  • 4
  • 29
  • 59
  • The answer is here : `System.out.println(found);// here i am getting null` So this line `depRepo.findByNDeptId(1)` returns nothing. Either mock this call or fix it (I don't know why it should return something, do you have some test DataSource that you are using for tests or how it works??) – ikos23 May 02 '18 at 14:13
  • I am using H2 database. I am not getting why `depRepo.findByNDeptId(1)` coming null – SpringUser May 02 '18 at 14:18
  • Add your Department code as well !!! – ikos23 May 03 '18 at 13:25

1 Answers1

1

This might be helpful!

The problem is here : Department found = depRepo.findByNDeptId(1); You expect data to be returned instead of null.

By default, tests annotated with @DataJpaTest will use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource).

So based on what you provided in your question:

  • Check if you have test data you expect. You need to have that record with ID = 1 in your in-memory database or the DB you use.
  • If you don't have you need to prepare some test data first (e.g. in your test class add @BeforeClass method where you can insert some test data before running your test)
  • Maybe when you create your test data using entityManager (this line entityManager.merge(dep);) it saves it to another DB? Not the one you are reading after? Anyway, it's better to create test before you run your test.

E.g.

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

Update:

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

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

According to this code, there is a sequence on your database, that is responsible for creating IDs for new records.

Basically how it works: when you save the new record, something like sequence get me next id is called and you are getting the ID.

That's why even if you set something to the ID (what you should not do), you are getting a completely different number!

So, that's how you could modify your test:

@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);
} 
ikos23
  • 4,879
  • 10
  • 41
  • 60
  • I got why I am getting null pointer exception. I am setting setnDeptId as 1 but in DB its saving 50. but why its saving 50 not 1 – SpringUser May 03 '18 at 12:56
  • @SpringUser it requires some debugging I guess. Can you try to save your test record with `em.persist(dep)` instead of `em.merge(dep)`? And check if it makes any difference. – ikos23 May 03 '18 at 13:07
  • @SpringUser why you are using merge there by the way ? – ikos23 May 03 '18 at 13:08
  • If i am using `em.persist(dep)` I am getting `persistenceException`. In some post i read solution for that we can use `merge` instead of `persist` – SpringUser May 03 '18 at 13:17
  • if I am using `depRepo.save(dep)` then also i am getting 50 – SpringUser May 03 '18 at 13:18
  • @SpringUser Well, first of all, there is a difference :) A good explanation can be found [here](https://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge). Have you figured out why you are getting an exception on `persist`? You need it instead of `merge`, so I would rather start fixing exception with `persist` – ikos23 May 03 '18 at 13:23
  • @SpringUser try `persist` but provide some ID like 1234. maybe there is already a record with id = 1 and that is why it fails – ikos23 May 03 '18 at 13:25
  • @SpringUser please provide the code for an entity (Department) and also stack trace with info about the exception on persist. Add those to the question. – ikos23 May 03 '18 at 13:32
  • I tried this but primary key is not auto incrementing if i set other value in department I am getting checkpoints value as `null, 50 , 50` – SpringUser May 03 '18 at 14:07