MockBean странный в успокаивающих сервисах - PullRequest
0 голосов
/ 06 августа 2020

Я сделал контроллер отдыха, который вызывает класс @service:

@Service
public class UnitServiceImpl extends HttpRequestServiceImpl implements UnitService {

    @Override
    public Unit addUnit(String unitName) {
        final Unit unit = new Unit();
        unit.setUnitName(unitName);
        return unitRepository.save(unit);
    }
    @Override
    public Unit getUnit(int id) {
        final Unit unit = unitRepository.findById(id);
        if (unit == null) {
            throw new EntityNotFoundException("Unit is not found");
        }
        return unit;
    }

    @Override
    public Iterable<Unit> getAllUnits() {
        return unitRepository.findAll();
    }
}

EnityNotFoundException обрабатывается ExceptionHandlingController:

@RestController
@ControllerAdvice
public class ExceptionHandlingController extends ResponseEntityExceptionHandler {

    @ExceptionHandler({RuntimeException.class})
    public final ResponseEntity<ErrorDetails> handleRuntimeException(RuntimeException ex, WebRequest request) {
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
                request.getDescription(false));
        HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
        if (ex.getClass() == EntityNotFoundException.class) {
            httpStatus = HttpStatus.NOT_FOUND;
        }
        return new ResponseEntity<>(errorDetails, httpStatus);
    }
}

Контроллер устройства просто вызывает getUnit:

@RestController
public class UnitController {
    private final UnitService managementService;


    @PostMapping(value = "/unit", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Unit> addUnit(HttpServletRequest request) throws FieldsIsAbsentException {
        final String unitName = managementService.getParameter(request, "unit_name");

        final Unit unit = managementService.addUnit(unitName);
        return new ResponseEntity<>(unit, HttpStatus.CREATED);
    }
    public UnitController(UnitService managementService) {
        this.managementService = managementService;
    }

    @GetMapping(value = "/unit", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Iterable<Unit>> getAllUnits() {
        final Iterable<Unit> allUnits = managementService.getAllUnits();
        return new ResponseEntity<>(allUnits, HttpStatus.OK);
    }

    @GetMapping(value = "/unit/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Unit> getUnitById(@PathVariable("id") int id) {
        final Unit unit = managementService.getUnit(id);
        return new ResponseEntity<>(unit, HttpStatus.CREATED);
    }
}

Теперь мне нужно протестировать их и создать метод модульного теста, который должен проверять ошибку 404:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration
class UnitControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    UnitService unitService;

    @MockBean
    UnitRepository unitRepository;

    @Autowired
    private UnitController unitController;

    private List<Unit> units;

    @Before
    public void initUnits() {
        units = new ArrayList<>();
        Unit unitWithName = new Unit();
        unitWithName.setId(1);
        unitWithName.setUnitName("NameUnit");
        units.add(unitWithName);

        Unit unitWithoutName = new Unit();
        unitWithoutName.setId(2);
        units.add(unitWithoutName);
    }

    @Test
    void contextLoads() {
        Assert.assertNotNull(unitController);
    }

    @Test
    void testGetAllUnits() throws Exception {
        given(this.unitService.getAllUnits()).willReturn(units);
        mockMvc.perform(get("/unit"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    void testUnitNotFound() throws Exception {
        int id = -1;
        given(this.unitRepository.findById(id)).willReturn(null);
        mockMvc.perform(get("/unit/-1"))
                .andExpect(status().isNotFound())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }
}

Когда я запускаю тесты, testGetAllUnits не работает:

java.lang.AssertionError: Content type not set

и testUnitNotFound выдает ошибку:

java.lang.AssertionError: Status expected:<404> but was:<201>

Но когда я удалю

@MockBean
UnitService unitService;

, он будет работать. В чем проблема?

ОБНОВЛЕНИЕ: у меня сейчас аналогичная проблема. Этот код вставляет в базу данных информацию об объекте. Но я сделал макет метода.

    @Test
    void testAddUnit() throws Exception {
        Unit unit = new Unit();
        unit.setId(1);
        unit.setUnitName("TestUnit");

        given(unitService.addUnit("TestUnit")).willReturn(unit);
        mockMvc.perform(post("/unit").param("unit_name", "TestUnit"))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.unitName").value("TestUnit"))
                .andExpect(jsonPath("$.id").value(1));
    }

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Вы издеваетесь не над тем bean. Бин, генерирующий исключение, - это служебный компонент, так что имитируйте это.

@Test
void testUnitNotFound() throws Exception {
    int id = -1;
    given(this.service.getUnit(id)).willThrow(new EntityNotFoundException("Unit is not found"));
    mockMvc.perform(get("/unit/-1"))
            .andExpect(status().isNotFound())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
0 голосов
/ 06 августа 2020

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

Если сервис имитируется, то реализация не вызывается . Возвращается только значение по умолчанию null. И, следовательно, никакое исключение не генерируется, как ожидалось ...

Если вы хотите иметь гибкость, позволяющую имитировать большую часть службы, но с остальными, вызываемыми их исходными реализациями, тогда вам следует изменить:

@MockBean
UnitService unitService;

в

@SpyBean
UnitService unitService;
...