Как сделать чтобы во время тестов кастомный валидатор автовайрил репоизторий?

156
25 февраля 2019, 05:20

Использую валидатор для проверки уникальности номера. В валидаторе автовайрю репозиторий для поиска по БД. Валидатор работает, но при запуске тестов валидатор не хочет автовайрить репозиторий и тесты не проходит. Как победить эту беду?

Сама сущность:

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
@Entity
@Table(name = "phone")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Phone implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;
    @Column(name = "phone_number")
    private Integer phoneNumber;
    // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Integer getPhoneNumber() {
        return phoneNumber;
    }
    public Phone phoneNumber(Integer phoneNumber) {
        this.phoneNumber = phoneNumber;
        return this;
    }
    public void setPhoneNumber(Integer phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
    // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Phone phone = (Phone) o;
        if (phone.getId() == null || getId() == null) {
            return false;
        }
        return Objects.equals(getId(), phone.getId());
    }
    @Override
    public int hashCode() {
        return Objects.hashCode(getId());
    }
    @Override
    public String toString() {
        return "Phone{" +
            "id=" + getId() +
            ", phoneNumber=" + getPhoneNumber() +
            "}";
    }
}

Валидатор:

import org.jhipster.blog.repository.PhoneRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Component
public class ContactNumberValidator implements ConstraintValidator<ContactNumberConstraint, Integer> {
    @Autowired
    private PhoneRepository repository;
    @Override
    public void initialize(ContactNumberConstraint phoneNumber) {
    }
    public ContactNumberValidator() {
    }
    @Override
    public boolean isValid(Integer phoneNumber,
                           ConstraintValidatorContext cxt) {
        Phone result = repository.findFirstByPhoneNumber(phoneNumber);
        boolean b = result == null;
        return b;
    }
}

Контроллер в котором осуществляется валидация:

@RestController
@RequestMapping("/api")
public class PhoneResource {
    private final Logger log = LoggerFactory.getLogger(PhoneResource.class);
    private static final String ENTITY_NAME = "phone";
    private final PhoneService phoneService;
    public PhoneResource(PhoneService phoneService) {
        this.phoneService = phoneService;
    }
    /**
     * POST  /phones : Create a new phone.
     *
     * @param phoneDTO the phoneDTO to create
     * @return the ResponseEntity with status 201 (Created) and with body the new phoneDTO, or with status 400 (Bad Request) if the phone has already an ID
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/phones")
    @Timed
    public ResponseEntity<PhoneDTO> createPhone(@RequestBody @Valid PhoneDTO phoneDTO) throws URISyntaxException {
        log.debug("REST request to save Phone : {}", phoneDTO);
        if (phoneDTO.getId() != null) {
            throw new BadRequestAlertException("A new phone cannot already have an ID", ENTITY_NAME, "idexists");
        }
        PhoneDTO result = phoneService.save(phoneDTO);
        return ResponseEntity.created(new URI("/api/phones/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }
...
}

Тест:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = BlogApp.class)
public class PhoneResourceIntTest {
    private static final Integer DEFAULT_PHONE_NUMBER = 1;
    private static final Integer UPDATED_PHONE_NUMBER = 2;
    @Autowired
    private PhoneRepository phoneRepository;

    @Autowired
    private PhoneMapper phoneMapper;

    @Autowired
    private PhoneService phoneService;
    @Autowired
    private MappingJackson2HttpMessageConverter jacksonMessageConverter;
    @Autowired
    private PageableHandlerMethodArgumentResolver pageableArgumentResolver;
    @Autowired
    private ExceptionTranslator exceptionTranslator;
    @Autowired
    private EntityManager em;

    private MockMvc restPhoneMockMvc;
    private Phone phone;
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        final PhoneResource phoneResource = new PhoneResource(phoneService);
        this.restPhoneMockMvc = MockMvcBuilders.standaloneSetup(phoneResource)
            .setCustomArgumentResolvers(pageableArgumentResolver)
            .setControllerAdvice(exceptionTranslator)
            .setConversionService(createFormattingConversionService())
            .setMessageConverters(jacksonMessageConverter).build();
    }
    /**
     * Create an entity for this test.
     *
     * This is a static method, as tests for other entities might also need it,
     * if they test an entity which requires the current entity.
     */
    public static Phone createEntity(EntityManager em) {
        Phone phone = new Phone()
            .phoneNumber(DEFAULT_PHONE_NUMBER);
        return phone;
    }
    @Before
    public void initTest() {
        phone = createEntity(em);
    }
    @Test
    @Transactional
    public void createPhone() throws Exception {
        int databaseSizeBeforeCreate = phoneRepository.findAll().size();
        // Create the Phone
        PhoneDTO phoneDTO = phoneMapper.toDto(phone);
        restPhoneMockMvc.perform(post("/api/phones")
            .contentType(TestUtil.APPLICATION_JSON_UTF8)
            .content(TestUtil.convertObjectToJsonBytes(phoneDTO)))
            .andExpect(status().isCreated());
        // Validate the Phone in the database
        List<Phone> phoneList = phoneRepository.findAll();
        assertThat(phoneList).hasSize(databaseSizeBeforeCreate + 1);
        Phone testPhone = phoneList.get(phoneList.size() - 1);
        assertThat(testPhone.getPhoneNumber()).isEqualTo(DEFAULT_PHONE_NUMBER);
    }
...
}
Answer 1

С тестированием познакомился (в том числе и мокито) буквально на прошлой неделе, мне совсем не понятно для чего так тест "городить". Задача простая, проверить корректность метода ContactNumberValidator #isValid().

Что для этого нужно ?

Я вижу это так:

  1. Нужен мок/спай ContactNumberValidator,
  2. Чтобы при вызове isValid() метод правильно отработал нужен мок для PhoneRepository, с тем чтобы можно было сделать стаббинг для метода findFirstByPhoneNumber, который подсунет прямо в тесте же созданные объект - тут ничего не нужно вычитывать из базы..

Да, но чтобы иметь возможность использовать мок репозитория в тестовом методе (isValid имеется в виду) придется добавить геттер для репозитория в ContactNumberValidator, с помощью него можно будет сделать стаббинг геттера, который (репозиторий) будет создан в тесте в виде мока.

Phone result = getRepository().findFirstByPhoneNumber(phoneNumber);

Возможно, это некрасиво выглядит, но все выше описанное должно быть сведено к простой конструкции (это схема близка к тому что должно работать):

@Test
public void dummy() {
    ContactNumberValidator validator = spy(ContactNumberValidator.class);
    Integer phoneNumer = Integer.valueOf(12345);
    ConstraintValidatorContext ctx = new ConstraintValidatorContext();
    PhoneRepository repository = spy(PhoneRepository.class);
    Phone phone = new Phone();
    doReturn(repository).when(validator).getRepository();
    doReturn(phone).when(repository).findFirstByPhoneNumber(anyInt());
    bolean actual = validator.isValid(phoneNumer, ctx);
    Assert.assertFalse(actual);
}
READ ALSO
Редактирование степени числа

Редактирование степени числа

Как замечательно что есть такой форум на котором можно задавать вопросыПотому что голову уже сломал

134
postgresql удаленное подключение

postgresql удаленное подключение

Помогите подключиться к базе данных удаленнопробовал настроить сервер, но не могу понять как подключиться к нему удаленно

398
не создается объект

не создается объект

У менять есть кнопка Start, в ней я создаю объект и добавляю его для видимости (и это работает), есть другая кнопка newGame, по сути я там делаю тоже...

153
Искажение русского текста, Java RMI

Искажение русского текста, Java RMI

Есть клиент и сервер на Java RMIКлиент считывает текст с консоли через Scanner

143