Reputation: 817
I am testing a function of my Signup class, however every time I run it a NullPointerException occurs inside the first if statement it enters at:
pass.show()
I suspect it is has something to do with not testing the app with an emulator. How can I prevent errors of creating a Toast when I am testing this?
Function in Signup 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 method:
@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));
}
Upvotes: 3
Views: 1547
Reputation: 60251
You'll need to decouple Toast
from your function. To do that, follow the below step, where I use your shown example and implement them exactly as per your need. Hopes this answer your inquiry, and you could able to follow through.
First create an interface for printing (toasting)
interface Printer {
void print(String message);
}
Then make your Signup
class implements the Printer
decouple the Toast
from your function. I believe your Signup
is an 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();
}
}
Then now, remove your Toast
in your checkInput
function, and perform the printing through the printer
sent to the function
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;
}
}
Note: whichever function that calls checkInput
from your class would need to send in the Printer
, which is actually this
if it is in Signup
class e.g.
checkInput(testUser, testEmail, testPass, testConfirmPass, this)l;
Now in your test, just implement the Mock Printer
e.g.
@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);
}
}));
}
With that, you could have your test done as per your desire, while your App still print through Toast
Upvotes: 1
Reputation: 306
Instead of passing the Toast on variable 'pass', just directly type 'Toast' and click the second suggestion.the I also remove your return.
This is the problem that I've seen on your code:
Toast pass = Toast.makeText (.....);
if you want to put it on variable, do like this
Toast pass = new Toast(getContext());
pass.makeText (.....).show();
or
pass.makeText(....);
pass.show();
so my suggestion is the option to and try this:
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();
}
}
Upvotes: -1
Reputation: 1834
If what you want to do is UnitTesting then you need to decouple your code for the Android stuff (like Toast).
A way to go is create an interface to display a Toast (or handle any Android related component) so you can mock it.
For example:
public interface AndroidInteraction (){
void showToast(Context context, String text, int length);
}
And implement that interface in your 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();
}
And finally your Signup class should be aware of that interface, so you could pass it throw it's constructor:
AndroidInteraction androidInteraction;
public Signup (AndroidInteraction androidInteraction){
this.androidInteraction = androidInteraction;
}
So your method now will look like (only one if clause to show how to use it, not the whole method):
if (!password.equals(confirmpassword)) {
androidInteraction.showToast(Signup.this, "Passwords don't match!", Toast.LENGTH_SHORT);
return false;
}
And you will need to mock that interface in your test and pass it to the class constructor
Upvotes: 1