Home > front end >  Field annotated with @Transient being persisted in @DataJpaTest
Field annotated with @Transient being persisted in @DataJpaTest

Time:05-04

I'm practicing TDD, So now I'm trying to make a test that will fail for now. About to test a @Entity that don't have a field relationship mapped so far. So I'm expecting my test to fail.

Here is TableA entity, you may notice that the TableB relationship is annotated with @Transient, so this field does not get persisted and don't get errors when running other integration tests ( tests that uses @RunWith(SpringRunner.class).

@Builder
@Table(name = "table_a")
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class TableAData {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Setter
    private String name;

    @Transient
    @Builder.Default
    private List<TableBData> tableBs = List.of();
}

Here is the code for TableB entity, nothing really interesting about it.

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "table_b")
public class TableBData {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Setter
    private String name;

}

I also have a TableAJpaRepository, this extends JpaRepository<TableAData, Long>:

public interface TableAJpaRepository extends JpaRepository<TableAData, Long> {

    public Optional<TableAData> findByName(String name);

}

My question is: Why does the follow test is not falling?

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

    @Autowired
    private TableAJpaRepository repository;

    @Test
    public void dataFechedByIdWhenGetTableBsShouldBringTableB() {
        TableBData tableBItem = TableBData.builder()
            .name("123 Test")
            .build();

        TableAData tableAItem = TableAData.builder()
            .name("TableAEntryName")
            .tableBs(List.of(tableBItem))
            .build();

        Long id = repository.save(archetype).getId();
        repository.flush();


        TableAData fetched = repository.getOne(id);
        assertThat(fetched.getTableBs()).isNotEmpty(); // This should be falling
        assertThat(fetched.getTableBs().get(0).getName()).isEqualTo("123 Test");
    }

}

Looks like getTableBs method is returning the other table entity from relationship, but I don't have it mapped. Am I missing something?

CodePudding user response:

So my friend and I spent some time trying to figure out what was going on. We've found this github issue that describes exactly the same issue. The person who open the issue also create a repo with a minimum reproducible example. One other thing that helped a lot was this SO answer: You fell in the trap of JPAs first level cache.

Looks like it's because of a cache.

To summarize, the solution was:

  • Inject TestEntityManager to persist and setup test scenario.
  • Always using TestEntityManager.persistAndFlush() method.
  • Call TestEntityManager.clear() before starting tests.
  • Repositories was used normally in test cases.
  • Related