programing

스프링 부트 테스트 @ 트랜잭션이 저장되지 않음

javamemo 2023. 6. 19. 21:05
반응형

스프링 부트 테스트 @ 트랜잭션이 저장되지 않음

저는 e2e 사용 사례를 테스트하기 위해 스프링 부트 테스트를 사용하여 간단한 통합 테스트를 하려고 합니다.데이터를 저장하는 저장소를 만들 수 없기 때문에 테스트가 작동하지 않습니다. 스프링 컨텍스트에 문제가 있는 것 같습니다.

내 엔티티입니다.

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    @Id
    private int id;
    private String name;
}

사용자 저장소입니다.

@Repository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}

사용자 서비스:

@Service
public class PersonService {

    @Autowired
    private PersonRepository repository;

    public Person createPerson(int id,String name) {
       return repository.save(new Person(id, name));
    }

    public List<Person> getPersons() {
      return repository.findAll();
    }
}

사용자 컨트롤러:

@RequestMapping
@RestController
public class PersonController {

  @Autowired
  private PersonService personService;

  @RequestMapping("/persons")
  public List<Person> getPersons() {
      return personService.getPersons();
  }

}

기본 응용 프로그램 클래스:

@SpringBootApplication
public class BootIntegrationTestApplication {

  public static void main(String[] args) {
    SpringApplication.run(BootIntegrationTestApplication.class, args);
  }
}

application.properties 파일:

spring.datasource.url= jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

그리고 테스트:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BootIntegrationTestApplicationTests {

    @Autowired
    private PersonService personService;
    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    @Transactional
    public void contextLoads() {
        Person person = personService.createPerson(1, "person1");
        Assert.assertNotNull(person);

        ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
    }
}

서비스가 사용자 엔티티를 저장하지 않기 때문에 테스트가 작동하지 않습니다.잘 부탁드립니다.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SmokeTest {

    @Autowired
    UserController userController;

    @Autowired
    UserDao userDAO;

    @Rollback(false) // This is key to avoid rollback.
    @Test   
    public void contextLoads() throws Exception {
        System.out.println("Hiren");

        System.out.println("started");
        userDAO.save(new User("tyx", "x@x.com"));
    }
}

참조하다@Rollback(false)롤백을 방지하는 데 중요합니다.

M 덕분에.Deinum 씨, 이해합니다. 따라서 테스트의 논리를 두 가지 테스트로 구분하는 것이 가장 좋습니다. 첫 번째는 서비스만 테스트하는 것이고 두 번째는 컨트롤러입니다.

테스트 1:

@Test
@Transactional
public void testServiceSaveAndRead() {
    personService.createPerson(1, "person1");
    Assert.assertTrue(personService.getPersons().size() == 1);
}

테스트 2:

@MockBean
private PersonService personService;

@Before
public void setUp() {
    //mock the service
    given(personService.getPersons())
            .willReturn(Collections.singletonList(new Person(1, "p1")));
}

@Test
public void testController() {
    ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
    Assert.assertTrue(persons.getBody()!=null && persons.getBody().length == 1);
}

엔티티를 저장하기 위한 스프링에는 트랜잭션이 필요합니다.그러나 트랜잭션이 커밋되기 전까지는 다른 트랜잭션에서 변경 사항을 볼 수 없습니다.

가장 간단한 방법은 커밋 트랜잭션 후 컨트롤러 호출

@Test
@Transactional
public void contextLoads() {
    Person person = personService.createPerson(1, "person1");
    Assert.assertNotNull(person);

    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            ResponseEntity<Person[]> persons = restTemplate.getForEntity("/persons", Person[].class);
        }
    });        
}

각각@Test변경사항을 영구적으로 유지하려면 DB 트랜잭션을 수행하는 기능을 사용할 수 있습니다.@Rollback(false)

@Rollback(false)
@Test
public void createPerson() throws Exception {
    int databaseSizeBeforeCreate = personRepository.findAll().size();

    // Create the Person
    restPersonMockMvc.perform(post("/api/people")
        .contentType(TestUtil.APPLICATION_JSON_UTF8)
        .content(TestUtil.convertObjectToJsonBytes(person)))
        .andExpect(status().isCreated());

    // Validate the Person in the database
    List<Person> personList = personRepository.findAll();
    assertThat(personList).hasSize(databaseSizeBeforeCreate + 1);
    Person testPerson = personList.get(personList.size() - 1);
    assertThat(testPerson.getFirstName()).isEqualTo(DEFAULT_FIRST_NAME);
    assertThat(testPerson.getLastName()).isEqualTo(DEFAULT_LAST_NAME);
    assertThat(testPerson.getAge()).isEqualTo(DEFAULT_AGE);
    assertThat(testPerson.getCity()).isEqualTo(DEFAULT_CITY);
}

jHipster에서 생성한 SpringBoot 프로젝트를 사용하여 테스트했습니다.

  • 스프링 부트: 1.5.4
  • j유닛 4.12
  • 봄 4.3.9

테스트가 실행되는 순서에 주의하십시오. @Commit 또는 @Rollback(false) 주석이 있는 테스트가 먼저 실행되어야 합니다. https://www.baeldung.com/junit-5-test-order

사용 안 함@Rollback(false)단위 검정은 데이터를 생성하지 않아야 합니다.

JPA 플러시 모드는AUTO(기본값 - 쿼리 발생 시 INSERT/UPDATE/DELETE SQL 플러시) /COMMIT.

작업 엔티티에 FLASH를 강제로 적용하거나 EntityManager를 사용하여 강제로 플러시하도록 쿼리하기만 하면 됩니다.

@Test
public void testCreate(){
    InvoiceRange range = service.createInvoiceRange(1, InvoiceRangeCreate.builder()
            .form("01GTKT0/010")
            .serial("NV/18E")
            .effectiveDate(LocalDate.now())
            .rangeFrom(1L)
            .rangeTo(1000L)
            .build(), new byte[] {1,2,3,4,5});

    service.findByCriteria(1, "01GTKT0/010", "NV/18E");  // force flush
    // em.flush(); // another way is using entityManager for force flush
}

언급URL : https://stackoverflow.com/questions/43658630/spring-boot-test-transactional-not-saving

반응형