복붙노트

[SPRING] 봄 부팅 테스트 @ 거래가 저장되지 않음

SPRING

봄 부팅 테스트 @ 거래가 저장되지 않음

나는 e2e 유즈 케이스를 테스트하기 위해 Spring Boot Test를 사용하여 간단한 통합 테스트를 시도하고있다. 저장소를 데이터를 저장할 수 없기 때문에 내 테스트가 작동하지 않는다. 스프링 컨텍스트에 문제가 있다고 생각한다.

이것은 나의 실체입니다.

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

이는 Person 저장소입니다.

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

서비스가 Person 엔티티를 저장하지 않기 때문에 테스트가 작동하지 않습니다. 미리 감사드립니다.

해결법

  1. ==============================

    1.M. Deinum에게 감사드립니다. 따라서 테스트의 논리를 두 가지 테스트로 구분하는 것이 가장 좋습니다. 첫 번째 테스트는 서비스 만 테스트하므로 (이 경우 트랜잭션 일 수 있음) 두 번째 테스트는 컨트롤러입니다.

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

    언젠가 누군가에게 도움이되기를 바랍니다.

  2. ==============================

    2.DB 트랜잭션을 만드는 각 @Test 함수에 대해 변경 사항을 영구적으로 유지하려면 @Rollback (false)을 사용할 수 있습니다.

    DB 트랜잭션을 만드는 각 @Test 함수에 대해 변경 사항을 영구적으로 유지하려면 @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 프로젝트로 테스트했습니다.

  3. ==============================

    3.

    @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)은 롤백을 피하기위한 키입니다.

  4. ==============================

    4.엔티티 저장을위한 스프링은 트랜잭션이 필요합니다. 그러나 트랜잭션이 커밋 될 때까지 변경 사항은 다른 트랜잭션에서 볼 수 없습니다.

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

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

    @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);
            }
        });        
    }
    
  5. from https://stackoverflow.com/questions/43658630/spring-boot-test-transactional-not-saving by cc-by-sa and MIT license