NullPointerException от Toast при модульном тестировании
Я тестирую функцию моего класса Registration, однако каждый раз, когда я ее запускаю, внутри первого оператора if возникает исключение NullPointerException:
pass.show()
Я подозреваю, что это как-то связано с не тестированием приложения с помощью эмулятора. Как я могу предотвратить ошибки при создании Toast, когда я тестирую это?
Функция в классе регистрации:
public boolean checkInput(String username, String email, String password, String confirmpassword) {
if (!email.contains("@") || !email.contains(".com")) {
Toast pass = Toast.makeText(Signup.this, "Email must be valid!", Toast.LENGTH_SHORT);
pass.show();
return false;
}
if (!password.equals(confirmpassword)) {
Toast pass = Toast.makeText(Signup.this, "Passwords don't match!", Toast.LENGTH_SHORT);
pass.show();
return false;
}
if (!(password.length() >= 6)) {
Toast pass = Toast.makeText(Signup.this, "Password must be at least 6 characters", Toast.LENGTH_SHORT);
pass.show();
return false;
}
else {
return true;
}
}
Метод испытания:
@Test
public void testInvalidEmail() {
String testUser = "testUser";
String testEmail = "testEmail.com"; //invalid
String testPass = "testPass";
String testConfirmPass = "testPass";
assertFalse(signupClass.checkInput(testUser,testEmail,testPass,testConfirmPass));
}
3 ответа
Вам нужно будет отделить Toast
от вашей функции. Чтобы сделать это, выполните следующий шаг, где я использую ваш показанный пример и реализую их точно так, как вам нужно. Надеется, что ответ на ваш запрос, и вы могли бы выполнить.
Сначала создайте интерфейс для печати (тост)
interface Printer {
void print(String message);
}
Тогда сделай свой Signup
класс реализует Printer
отделить Toast
от вашей функции. Я верю твоему Signup
является Activity
,
public class Signup extends AppCompatActivity implements Printer {
// ... other codes ...
@Override
public void print(String message) {
Toast pass = Toast.makeText(Signup.this, message, Toast.LENGTH_SHORT);
pass.show();
}
}
Затем удалите Toast
в вашем checkInput
и выполнить печать через printer
отправлен в функцию
public boolean checkInput(String username, String email, String password, String confirmpassword, Printer printer) {
if (!email.contains("@") || !email.contains(".com")) {
printer.print("Email must be valid!");
return false;
}
if (!password.equals(confirmpassword)) {
printer.print("Passwords don't match!");
return false;
}
if (!(password.length() >= 6)) {
printer.print("Password must be at least 6 characters");
return false;
}
else {
return true;
}
}
Примечание: какая функция вызывает checkInput
от вашего класса нужно будет отправить в Printer
что на самом деле this
если это в Signup
класс например
checkInput(testUser, testEmail, testPass, testConfirmPass, this)l;
Теперь в вашем тесте, просто внедрите макет Printer
например
@Test
public void testInvalidEmail(MainActivity mainActivity) {
String testUser = "testUser";
String testEmail = "testEmail.com"; //invalid
String testPass = "testPass";
String testConfirmPass = "testPass";
assertFalse(signUp.checkInput(testUser, testEmail, testPass, testConfirmPass, new Printer() {
@Override
public void print(String message) {
System.out.println(message);
}
}));
}
При этом вы можете выполнить тест по своему желанию, в то время как ваше приложение все еще печатает через Toast
Если вы хотите использовать UnitTesting, то вам нужно отделить код для Android-приложений (например, Toast).
Одним из способов является создание интерфейса для отображения Toast (или обработки любого компонента, связанного с Android), чтобы вы могли его высмеивать.
Например:
public interface AndroidInteraction (){
void showToast(Context context, String text, int length);
}
И внедрите этот интерфейс в свою деятельность:
public class SignUpActivity extends AppCompatActivity implements AndroidInteraction{
.......
......
@Override
void showToast(Context context, String text, int length){
Toast pass = Toast.makeText(context, text, length);
pass.show();
}
И наконец, ваш класс Registration должен знать об этом интерфейсе, чтобы вы могли передать его через его конструктор:
AndroidInteraction androidInteraction;
public Signup (AndroidInteraction androidInteraction){
this.androidInteraction = androidInteraction;
}
Таким образом, теперь ваш метод будет выглядеть (только одно условие if, показывающее, как его использовать, а не весь метод):
if (!password.equals(confirmpassword)) {
androidInteraction.showToast(Signup.this, "Passwords don't match!", Toast.LENGTH_SHORT);
return false;
}
И вам нужно будет смоделировать этот интерфейс в вашем тесте и передать его конструктору класса
Вместо того, чтобы передавать Toast по переменной "pass", просто введите "Toast" и щелкните по второму предложению. Я также удаляю ваш возврат.
Это проблема, которую я видел в вашем коде:
Toast pass = Toast.makeText (.....);
если вы хотите поместить его в переменную, сделайте так
Toast pass = new Toast(getContext());
pass.makeText (.....).show();
или же
pass.makeText(....);
pass.show();
так что мое предложение это вариант и попробуйте это:
public boolean checkInput(String username, String email, String password, String confirmpassword) {
if (!email.contains("@") || !email.contains(".com")) {
Toast.makeText(Signup.this, "Email must be valid!", Toast.LENGTH_SHORT).show();
}
if (!password.equals(confirmpassword)) {
Toast.makeText(Signup.this, "Passwords don't match!", Toast.LENGTH_SHORT).show();
}
if (!(password.length() >= 6)) {
Toast pass = Toast.makeText(Signup.this, "Password must be at least 6 characters", Toast.LENGTH_SHORT).show();
}
}