Месяц назад мы приняли участие в конференции SQA Days. Наши эксперты выступили с докладом (вот презентация, ждите подробную статью и видео выступления) и провели ряд активностей на стенде. Сегодня мы хотим рассказать об одной из них – и интересна она тем, что по факту это задание, которое в «AliExpress Россия» используется на собеседования тестировщиков.

В этом материале мы расскажем о предыстории появления тестового задания, его эволюции и дадим возможность всем желающим проверить свои силы в поисках багов.

Предыстория

Раньше на собеседованиях со специалистами по тестированию в компании давали соискателям тестовое задание на поиск багов. Интересный факт заключался в том, что оно было теоретическим – то есть никакой реальной системы человек не получал, мы просто ее описывали на словах и предлагали порассуждать о том, как можно искать в ней баги.

Шли месяцы, и в какой-то момент мы подумали, что наглядность в такого рода задачах – это хорошо, и решили визуализировать наш тест. Выглядело все это так: мы создали простой эндпоинт, который принимал Post-запросы и отдавал ответы.

Простая программа принимала данные на вход и сообщала пользователю, введено число или нет. В этом «софте» из пары строк кода на Java + SpringBoot и нужно было искать баги. 

@RestController
@SpringBootApplication
@Slf4j
public class IsNumberApplication {

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

    @PostMapping(path = "/isnumber", consumes = "application/json", produces = "application/json")
    public IsNumberResponse hello(@RequestBody IsNumberRequest request) {
        String requestValue = request.value;
        log.info("Request value is '{}'", requestValue);

        boolean isNumber;
        try {
            Float.parseFloat(requestValue);
            isNumber = true;
        } catch (NumberFormatException e) {
            isNumber = requestValue.equals(Boolean.toString(true));
        }

        return new IsNumberResponse(isNumber);
    }
}

Причем тесты можно было попробовать автоматизировать – в качестве домашнего задания мы предлагали кандидатам написать автотесты на данный API.

Вот простенький пример теста на Java + Junit5 + RestAssured:

 @Test
    void positiveNumber() {
        RestAssured.with().contentType(ContentType.JSON)
                .body(new IsNumberBody(5))
                .post("/isnumber")
                .then()
                .statusCode(OK)
                .body("isNumber", equalTo(true));
    } 	

Такой подход и «открытое» задание без особенных ограничений позволяют хорошо раскрыть специалиста. Кто-то проверяет только очевидные моменты, а кто-то в своих исследованиях даже по такой простой фиче пытается докопаться до самых мелких деталей. В итоге именно это и подвигло нас доделать движок теста, реализовать полноценный фронтенд и доработать существующий бэкенд. 

Естественно, и во фронт-, и в бэк-части мы намеренно заложили ряд багов, которые и нужно было обнаружить. 

Тестовое задание и активность на конференции

Когда мы решили принять участие в конференции SQA Days, то встал вопрос, что мы там будем делать, помимо доклада. И тут пришла идея использовать наше тестовое задание в качестве одной из активностей на стенде. Тем, кто выполнил его, мы хотели дарить призовые купоны, которые можно потратить на AliExpress.

Конечно, для того чтобы превратить тестовое задание для проверки соискателей вакансий в интересную стендовую активность, требовались доработки. Мы решили, что проверяемая функция должна быть доступна внутри приложения AliExpress, а работать она будет с нашим, уже готовым бэкендом. Подготовить всё в срок нам помог наш фронтенд-разработчик (спасибо, Инал!).

Ниже – кусок кода фронта с заложенными багами:

const SqaDaysPage = () => {
  const [inputValue, setInputValue] = useState('');
  const [isShowAgain, setIsShowAgain] = useState(true);
  const [isFirstCall, setIsFirstCall] = useState(true);
  const {showModal, hideModal, activeModal} = useContext(ModalContext);

  const onSendAnswer = async () => {
    // Block request if it's the first call
    if (isFirstCall) {
      return setIsFirstCall(false);
    }
  
    setIsLoading(true);
  
    universalFetch('https://api.aliexpress.ru/***/***', {
      method: 'POST',
      headers: {},
      body: JSON.stringify({ value: inputValue }),
    }).then((response) => response.json())
      .then(({ error, isNumber }) => {
        setIsLoading(false);
  
        if (error)
          // some code...
  
        // Hardcode logic
        if (Number(requestData.value) === 0)
          isNumber = false;
  
        return toast.show({
          duration: 1500,
          type: isNumber ? 'default' : 'error',
          text: isNumber ? `Это число: ${inputValue}` : `Это не число: ${inputValue}`,
        });
      })
      .catch(() => {
        // some code...
      });
  };

  const onCloseWelcomePopup = () => {
    hideModal();

    // If true, show welcome popup again after 40 sec.
    if (isShowAgain) {
      setTimeout(() => {
        showModal({ id: WELCOME_POPUP });
        setIsShowAgain(false);
      }, 40000);
    }
  };

  return (
     {/* some code... */}
     <Button size="l" onClick={onSendAnswer} isLoading={isLoading} fullWidth style={style.sendButton}>
       Отправить
     </Button>

	 {/* Display welcome popup */}
	 <ModalComponent visible={activeModal?.id === WELCOME_POPUP} key={WELCOME_POPUP} onHide={onCloseWelcomePopup}>
       <View style={{ paddingLeft: 20, paddingRight: 20, width: 750 }}>
         {/* Show broken image in a second times */}
         <Image style={{ width: 192, height: 122, marginBottom: 20 }} source={{ uri: isShowAgain ? 'https://img.alicdn.com/imgextra/i2/O1CN01KbA7Vc1Q0ek2o2K7t_!!6000000001914-2-tps-186-118.png' : '' }} />
         <Typography type="h3">Тестовый стенд от AliExpress</Typography>
         <Typography style={{ marginBottom: 30 }}>
           Ваша задача найти все баги на данной странице. Также на этой странице есть несколько пасхалок, за нахождение которых вы можете получить приятные призы.
         </Typography>
         <Button size="l" onClick={onCloseWelcomePopup}>Закрыть</Button>
       </View>
     </ModalComponent>
     {/* some code... */}
  )
}

 Тест появлялся внутри мобильного браузера или приложения AliExpress после сканирования специального кода. 

QR-код для старта задания
QR-код для старта задания
Вот так выглядел тестовый стенд AliExpress
Вот так выглядел тестовый стенд AliExpress

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

  • первый раз при попытке отправить вводные данные ничего не происходило;

  • после закрытия поп-апа с приветствием он через какое-то время появлялся снова – уже с битой иконкой.

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

Попробуйте пройти наш тест и выиграйте купон на AliExpress

Мы будем развивать и видоизменять наше тестовое задание и дальше. Поиск заложенных багов будет сложнее. А пока мы хотим предложить задание в его текущем виде аудитории «Хабра».

Получить доступ к тесту можно по этой ссылке или отсканировав QR-код из поста выше камерой в приложении AliExpress. Первые 290 участников, отправивших решенное задание, получат подарочный купон на 100 рублей, которые можно потратить внутри AliExpress.

ВАЖНО: в системе есть еще один «баг»: купоны из мобильного браузера получить нельзя, испытание нужно проходить в приложении AliExpress.

***

На сегодня всё, спасибо за внимание! В следующих постах мы расскажем о локализации мобильного приложения «AliExpress Россия», работах по исправлению багов и развитию инфраструктуры.