单元测试时来自Toast的NullPointerException

问题描述 投票:0回答:3

我正在测试我的Signup类的一个函数,但是每次运行它时,NullPointerException都会在它输入的第一个if语句中发生:

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));
}
android junit android-toast
3个回答
0
投票

你需要将Toast与你的函数分离。为此,请按照以下步骤操作,我将使用您显示的示例并根据您的需要完全实现它们。希望这能回答您的询问,并且您能够完成。

首先创建一个打印界面(烘烤)

interface Printer {
    void print(String message);
}

然后让你的Signup类实现PrinterToast与你的函数分离。我相信你的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;

现在在你的测试中,只需实现Mock 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打印


1
投票

如果您想要做的是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();
    }

最后你的Signup类应该知道那个接口,所以你可以传递它抛出它的构造函数:

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;
}

您需要在测试中模拟该接口并将其传递给类构造函数


-1
投票

而不是在变量'pass'上传递Toast,只需直接输入'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();
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.