单元测试时来自 Toast 的 NullPointerException
NullPointerException from Toast while Unit Testing
我正在测试我的 Signup class 的一个功能,但是每次我 运行 它在第一个 if 语句中出现 NullPointerException:
pass.show()
我怀疑这与未使用模拟器测试应用程序有关。当我测试这个时,如何防止创建 Toast 的错误?
注册函数Class:
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 东西(比如 Toast)解耦你的代码。
一种方法是创建一个界面来显示 Toast(或处理任何 Android 相关组件),以便您可以模拟它。
例如:
public interface AndroidInteraction (){
void showToast(Context context, String text, int length);
}
并在您的 activity:
中实现该接口
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 class 应该知道那个接口,所以你可以通过它抛出它的构造函数:
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;
}
并且您需要在测试中模拟该接口并将其传递给 class 构造函数
不要在变量 'pass' 上传递 Toast,只需直接键入 'Toast' 并单击第二个 suggestion.the 我也删除你的 return。
这是我在您的代码中看到的问题:
吐司通=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();
}
}
您需要将 Toast
与您的函数分离。为此,请按照以下步骤操作,我将在其中使用您显示的示例并完全根据您的需要实施它们。希望这能回答您的问题,并且您能够跟进。
首先创建一个用于打印(toasting)的界面
interface Printer {
void print(String message);
}
然后让您的 Signup
class 实现 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();
}
}
那么现在,在你的checkInput
函数中删除你的Toast
,并通过发送到函数
的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;
}
}
注意:从您的 class 调用 checkInput
的任何函数都需要在 Printer
中发送,如果它在 [=16] 中,则实际上是 this
=] class 例如
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
进行打印
我正在测试我的 Signup class 的一个功能,但是每次我 运行 它在第一个 if 语句中出现 NullPointerException:
pass.show()
我怀疑这与未使用模拟器测试应用程序有关。当我测试这个时,如何防止创建 Toast 的错误?
注册函数Class:
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 东西(比如 Toast)解耦你的代码。
一种方法是创建一个界面来显示 Toast(或处理任何 Android 相关组件),以便您可以模拟它。
例如:
public interface AndroidInteraction (){
void showToast(Context context, String text, int length);
}
并在您的 activity:
中实现该接口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 class 应该知道那个接口,所以你可以通过它抛出它的构造函数:
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;
}
并且您需要在测试中模拟该接口并将其传递给 class 构造函数
不要在变量 'pass' 上传递 Toast,只需直接键入 'Toast' 并单击第二个 suggestion.the 我也删除你的 return。
这是我在您的代码中看到的问题:
吐司通=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();
}
}
您需要将 Toast
与您的函数分离。为此,请按照以下步骤操作,我将在其中使用您显示的示例并完全根据您的需要实施它们。希望这能回答您的问题,并且您能够跟进。
首先创建一个用于打印(toasting)的界面
interface Printer {
void print(String message);
}
然后让您的 Signup
class 实现 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();
}
}
那么现在,在你的checkInput
函数中删除你的Toast
,并通过发送到函数
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;
}
}
注意:从您的 class 调用 checkInput
的任何函数都需要在 Printer
中发送,如果它在 [=16] 中,则实际上是 this
=] class 例如
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