Вопрос или проблема
Интерактивная консоль при запуске юнит-тестов в Codeception
У нас есть 2 сценария:
- Привязка аккаунта (регистрация номера банковского счета к сервису)
- Подтверждение OTP (ввод кода OTP, отправленного на мобильный телефон клиента)
Некоторые ответы от привязки аккаунта использовались во втором сценарии, но мне нужно “вставить” значение кода OTP перед вторым шагом.
Что я сделал до сих пор в Codeception — использовал Codeception\Lib\Actor\Shared\Pause
:
public function testVerificationFlow()
{
$faker = Faker\Factory::create();
$sequence="0000";
$partnerReferenceNo = $faker->numerify('###########') . $sequence;
$bankAccountNo = $faker->numerify('##########');
$bankCardNo = $faker->randomNumber(4, true);
$limit = 250000.00;
$email = $faker->email();
$custIdMerchant = $faker->numerify('##########');
$response = $this->autopay->accountBinding(
$partnerReferenceNo,
$bankAccountNo,
$bankCardNo,
$limit,
$email,
$custIdMerchant
);
codecept_debug($response);
$this->assertEquals($response->responseCode, self::RESP_CODE_ACCOUNT_BINDING);
$otpCode="";
// как вставить значение $otpCode здесь?
$this->pause();
codecept_debug($otpCode);
$verifyOtpResponse = $this->autopay->verifyOtp(
$partnerReferenceNo,
$response->originalReferenceNo,
$response->chargeToken,
$otpCode,
);
codecept_debug($verifyOtpResponse);
$this->assertEquals($verifyOtpResponse->responseCode, self::RESP_CODE_OTP_VERIFY);
}
Проект Hoa\Console заброшен уже много лет назад
Выполнение ПРИОСТАНОВЛЕНО, начинается интерактивная оболочка...
Введите команды, чтобы попробовать их:
- ENTER для продолжения
- TAB для автозаполнения
- F5 для сохранения команды
- F6 для переключения автосохранения успешных команд
- F8 для просмотра сохраненных команд
- F10 для очистки сохраненных команд
Я все еще не знаю, что использовать, когда приостановлен модульный тест. Любые идеи / ключевые слова для поиска в Google будут признательны.
Я только что понял, что Hoa\Console
использует readline()
для “приостановки” процесса.
$otpCode = readline('Пожалуйста, введите OTP перед запуском testVerifyOtp: ');
$verifyOtpResponse = $this->autopay->verifyOtp(
$partnerReferenceNo,
$response->referenceNo,
$response->additionalInfo->chargeToken,
(string) $otpCode,
);
codecept_debug($verifyOtpResponse);
$this->assertEquals($verifyOtpResponse->responseCode, self::RESP_CODE_OTP_VERIFY);
Пожалуйста, введите OTP перед запуском testVerifyOtp: 364612
✔ AutopayTest: Проверка потока (9.85с)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Время: 00:09.862, Память: 10.00 МБ
OK (1 тест, 2 утверждения)
Это будет мое решение в чистой программе.
class OTP_Verify_Response {
protected $data_file = false;
protected $questions = array();
protected $responses = array();
public function __construct($data_file) {
if (!empty($data_file) and file_exists($data_file)) {
$this->data_file = realpath($data_file);
}
if (!empty($this->data_file)) {
$data = file_get_contents($this->data_file);
$data = json_decode($data, true);
} else {
$data = array();
}
$this->questions = $data['questions'];
$this->responses = $data['responses'];
}
public function doQuestions() {
if ($question_answer = $this->_askQuestion("Пожалуйста, введите OTP перед запуском testVerifyOtp:", "testVerifyOtp")) {
$this->_testVerifyOtp($question_answer); // Это было отвечено
} else {
return false; // Нам нужен ответ
}
// Зададим другой вопрос ...
return $this->closeDataFile();
}
protected function _testVerifyOtp($question_answer) {
// делаем что-то с $question_answer
}
protected function _askQuestion($question_text, $question_field) {
if (empty($question_text)) {
return false;
}
if (!empty($_POST) and array_key_exists($question_field, $_POST)) {
$question_answer = $_POST[$question_field];
$this->_storeAnswer($question_text, $posted_answer);
} elseif ($question_text and !empty($question_text)) {
$question_answer = $this->_answerQuestion($question_text);
} else {
$question_answer = false;
}
if (!empty($question_answer)) {
return $question_answer;
}
echo "<div>{$question_text}? <input name="{$question_field}" value="{$_POST[$question_field]}" /></div>";
return false;
}
protected function _answerQuestion($question_text) {
$question_hash = $this->_createQuestionHash($question_text);
if ($this->responses[$question_hash]) {
return $this->responses[$question_hash];
}
return false;
}
protected function _storeAnswer($question_text, $posted_answer) {
$question_hash = $this->_createQuestionHash($question_text);
$this->questions[$question_hash] = $question_text;
$this->responses[$question_hash] = $posted_answer;
return $posted_answer;
}
protected function _createQuestionHash($question_text) {
$question_hash = md5($question_text);
return $question_hash;
}
public function update_store_data() {
$store_data = array();
$store_data['questions'] = $this->questions;
$store_data['responses'] = $this->responses;
if (!empty($this->data_file)) {
return file_put_contents($this->data_file, json_encode($store_data));
}
return false;
}
public function closeDataFile() {
if (!empty($this->data_file) and file_exists($this->data_file)) {
return unlink($this->data_file);
}
return false;
}
}
Идея состоит в том, чтобы использовать POST, а также файл ДАННЫХ и сохранить каждый вопрос / ответ
$verify_item = new OTP_Verify_Response("/tempFile.tmp");
$verify_item->doQuestions();
(Вам нужно будет обернуть это в <form></form>
), но в идеале это будет работать.
Ответ или решение
Для решения задачи по внедрению значения кода OTP в процессе запуска модульного теста с использованием Codeception, вы сделали правильные шаги в направлении использования метода readline()
для паузы выполнения теста и получения пользовательского ввода. Давайте подытожим ключевые моменты и предложим полное решение.
Полное Решение
-
Импорт необходимых библиотек: Убедитесь, что вы используете все необходимые библиотеки. В данном случае вам может понадобиться
Faker
для генерации случайных данных, а также классreadline
для ввода данных. - Основной код теста: Мы добавим вызов
readline()
для получения кода OTP от пользователя, а также условия для проверки корректности этого кода и продолжения теста.
Ниже представлена переработанная версия вашего метода testVerificationFlow
с учетом предложенных изменений:
public function testVerificationFlow()
{
$faker = Faker\Factory::create();
$sequence = "0000";
$partnerReferenceNo = $faker->numerify('###########') . $sequence;
$bankAccountNo = $faker->numerify('##########');
$bankCardNo = $faker->randomNumber(4, true);
$limit = 250000.00;
$email = $faker->email();
$custIdMerchant = $faker->numerify('##########');
// Вызов метода для привязки счета
$response = $this->autopay->accountBinding(
$partnerReferenceNo,
$bankAccountNo,
$bankCardNo,
$limit,
$email,
$custIdMerchant
);
codecept_debug($response);
$this->assertEquals($response->responseCode, self::RESP_CODE_ACCOUNT_BINDING);
// Получение кода OTP от пользователя
$otpCode = readline('Пожалуйста, введите код OTP перед выполнением testVerifyOtp: ');
codecept_debug($otpCode);
// Проверка кода OTP
$verifyOtpResponse = $this->autopay->verifyOtp(
$partnerReferenceNo,
$response->originalReferenceNo,
$response->chargeToken,
(string)$otpCode
);
codecept_debug($verifyOtpResponse);
$this->assertEquals($verifyOtpResponse->responseCode, self::RESP_CODE_OTP_VERIFY);
}
Пояснение
-
Мы заменили линию с
pause()
наreadline()
, чтобы получить прямой ввод пользователя, который будет использоваться в следующем шаге теста. -
Ввод пользователя будет сохранен в переменную
$otpCode
, которая затем будет использована при вызове метода для проверки OTP. - Это позволяет вам взаимодействовать с тестом в интерактивном режиме, что упрощает процесс введения данных.
Заключение
Использование readline()
обеспечивает более эффективное и интуитивно понятное взаимодействие во время теста, позволяя вам вводить необходимые значения в реальном времени. Это решение полностью охватывает вашу задачу по внедрению значения кода OTP и должно сработать корректно в контексте вашего теста с Codeception.