I have the following test method:
#RunWith(MockitoJUnitRunner.class)
public class AccountManagerTest {
#InjectMocks
private AccountManager accountManager = new AccountManagerImpl(null);
#Mock
private AuthStorage authStorage;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
/* REGISTER TESTS */
#Test
public void test_whenRegister_withAlreadyExistingEmail_thenDoNotRegister() throws AuthStorageException {
String email = "foo#bar.com";
String name = "Foo";
String password = "123456";
String password2 = "123456";
doThrow(new AuthStorageException("Email already in use")).when(authStorage).registerNewUser(Matchers.any());
assertFalse(accountManager.register(email, name, password, password2));
}
}
that tests the following class method:
#Override
public Boolean register(String email, String name, String password, String password2) {
if (password.equals(password2)) {
try {
String pwd = hashPassword(password);
User user = new User(email, name, pwd);
AuthStorage authStorage = new AuthStorageImpl();
authStorage.registerNewUser(user);
return true;
} catch (NoSuchAlgorithmException | AuthStorageException e) {
return false;
}
}
// If passwords don't match
return false;
}
Supposedly, when calling registerNewUser it should thow an exception and then the method would return false, but when debugging I see that the exception isn't thrown and the program returns true. What am I doing wrong?
First of all you shouldn't instantiate the object where mocks are inserted:
#InjectMocks
private AccountManager accountManager = new AccountManagerImpl(null);
Instead, use this:
#InjectMocks
private AccountManager accountManager;
Then if you use Mockito runner:
#RunWith(MockitoJUnitRunner.class)
You shouldn't inject mocks directly:
#Before
public void setup() {
MockitoAnnotations.initMocks(this); //remove this line
}
And the last point: there is no point to your mocking because you have a local variable in your register method:
AuthStorage authStorage = new AuthStorageImpl();
authStorage.registerNewUser(user);
Which makes the class use your mocked object.
Related
I'm trying to write a unittest (test_myMethod) for one of my methods (myMethod) but I can't seem to get it to work. I get a NullPointer exception error with the code below. In my test it seems that the line myClass.otherMethod("hostName") in the unittest evaluates to Null so it can't do .getOSRevision(). Anyone know how I can get my unittest to pass?
MyClass.java
public class MyClass {
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
OtherMethod response = myClient.newMyMethodRevisionCall().call(
someObject.builder()
.withHostName(hostname)
.build()
);
return response;
}
}
MyClassTest.java
public class MyClassTest {
#Mock
private MyClient myClient;
#Mock
private MyMethodRevisionCall myMethodRevisionCall;
#Mock
private OtherMethod otherMethod;
private MyClass myClass;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
myClass = new MyClass(myClient);
}
// My failing unittest attempt
#Test
public void test_myMethod() {
when(myClass.otherMethod("hostName")
.getOSRevision()) //java.lang.NullPointerException happens on this line.
.thenReturn("TestString");
final String result = myClass.myMethod("TestString");
verify(myMethodRevisionCall, times(1)
}
}
You cannot use Mockito.when() on classes that are not mocked by Mockito. MyClass is not a mock. Instead you create an actual instance of it. Therefore, you need to actually run the code and not mock it. However, all dependencies of your class under test (MyClient in your case) you can mock.
This is a working example:
public class MyClass {
private MyClient myClient;
public MyClass(MyClient myClient) {
this.myClient = myClient;
}
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
return myClient.newMyMethodRevisionCall().call(new SomeObject(hostname));
}
}
class MyClassTest {
private MyClient myClient;
private MyClass myClass;
#BeforeEach
void setUp() {
myClient = mock(MyClient.class);
myClass = new MyClass(myClient);
}
#Test
public void test_myMethod() {
MyMethodRevisionCall myMethodRevisionCall = mock(MyMethodRevisionCall.class);
OtherMethod otherMethod = mock(OtherMethod.class);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
when(myMethodRevisionCall.call(any())).thenReturn(otherMethod);
when(otherMethod.getOSRevision()).thenReturn("revision");
final String result = myClass.myMethod("TestString");
assertEquals("revision", result);
verify(myMethodRevisionCall, times(1));
}
}
In below example i am trying to test both catch and try block using mockito. And also when the CustomException is raised then i want to call the method with second host. Thank you.
private static void getDetails()
{
final String host1 = "http://localhost:8080/springrestexample/employee/id";
final String host2 = "http://localhost:8080/springrestexample/student/id";
RestTemplate restTemplate = new RestTemplate();
String result = null;
try {
String result = restTemplate.getForObject(host1, String.class);
} catch(CustomException customException) {
String result = restTemplate.getForObject(host2, String.class);
}
return result;
}
Would it be possible to have restTemplate being passed to that method as an arg.
(If yes, then)
Using org.mockito.Mockito -> mock() you can mock like below,
RestTemplate restTemplateMock = mock(RestTemplate.class);
when(restTemplateMock.getForObject(host1)).thenThrow(CustomException.class);
Pass this mock object to your method and it will throw exception inside try.
Update: Sample test cases for your ref.
#Test
public void testGetDetails()
{
RestTemplate restTemplateMock = mock(RestTemplate.class);
when(restTemplateMock.getForObject(host1)).thenReturn(SOME_STRING);
String result = //call your method
assertThat(result).isEqualTo(SOME_STRING);
}
#Test
public void testGetDetailsUsesOtherHostWhenExceptionIsThrown()
{
RestTemplate restTemplateMock = mock(RestTemplate.class);
when(restTemplateMock.getForObject(host1)).thenThrow(CustomException.class);
when(restTemplateMock.getForObject(host2)).thenReturn(SOME_STRING);
String result = //call your method
assertThat(result).isEqualTo(SOME_STRING);
}
When you in need to use same mock object,
RestTemplate myRestTemplateMock = mock(RestTemplate.class);
#Test
public void testGetDetails()
{
when(myRestTemplateMock.getForObject(host1)).thenReturn(SOME_STRING);
String result = //call your method
assertThat(result).isEqualTo(SOME_STRING);
}
#Test
public void testGetDetailsUsesOtherHostWhenExceptionIsThrown()
{
when(myRestTemplateMock.getForObject(host1)).
thenThrow(CustomException.class);
when(myRestTemplateMock.getForObject(host2)).thenReturn(SOME_STRING);
String result = //call your method
assertThat(result).isEqualTo(SOME_STRING);
}
Ok, First of all, your original method needs to be like below. (since normal practice is we don't test private methods and if you need a static method to be tested you need something more than Mockito (PowerMock))
public class Example {
#Autowired
public RestTemplate restTemplate;
public String restTemplateTest()
{
final String host1 = "http://localhost:8080/springrestexample/employee/id";
final String host2 = "http://localhost:8080/springrestexample/student/id";
String result;
try {
result = restTemplate.getForObject(host1, String.class);
} catch(CustomException customException) {
result = restTemplate.getForObject(host2, String.class);
}
return result;
}
}
Below is the sample test for the above method.
public class ExampleTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private Example testExample;
#BeforeEach
public void setUp()
{
MockitoAnnotations.initMocks(this);
}
#Test
public void restTemplateTest() {
Mockito.when(restTemplate.getForObject(Mockito.eq("http://localhost:8080/springrestexample/employee/id"), Mockito.eq(String.class)))
.thenThrow(CustomException.class);
Mockito.when(restTemplate.getForObject(Mockito.eq("http://localhost:8080/springrestexample/student/id"), Mockito.eq(String.class)))
.thenReturn("expected");
testExample.restTemplateTest();
// if exception thrown , then rest template mock will invoke 2 times, otherwise
// 1
Mockito.verify(restTemplate, Mockito.times(2)).getForObject(Mockito.anyString(), Mockito.eq(String.class));
}
}
Below is the way to test when no Exception occurs scenario.
#Test
public void restTemplateTest_when_no_exception() {
Mockito.when(restTemplate.getForObject(Mockito.eq("http://localhost:8080/springrestexample/employee/id"), Mockito.eq(String.class)))
.thenReturn("expectedString");
String actual = testExample.restTemplateTest();
// if exception not thrown , then rest template mock will invoke 1 times, otherwise
// 1
Mockito.verify(restTemplate, Mockito.times(1)).getForObject(Mockito.anyString(), Mockito.eq(String.class));
Assert.assertEquals("expectedString",actual);
}
I'm trying to call the second method of this class, and always get null. Note that it returns new User() however in the test class I always get null:
#Stateless
public class UserDAO2 {
public Connection getConnFromPool(int i) {
return null;
}
public User readByUserid(String s) {
System.out.println("In DAO 2");
Connection c = getConnFromPool(1);
return new User();
}
}
And the test class:
#RunWith(MockitoJUnitRunner.class)
public class UserBeanUnitTest {
#InjectMocks
private UserDAO2 dao2;
#Before
public void setup() {
dao2 = Mockito.mock(UserDAO2.class);
MockitoAnnotations.initMocks(this);
}
#Test
public void testBean() {
Mockito.when(dao2.getConnFromPool(1)).thenReturn(null);
User expectedUser = new User();
expectedUser.setSk(1);
expectedUser.setFirstName("David");
expectedUser.setLastName("Gahan");
expectedUser.setUserid("user1");
User user = dao2.readByUserid("user1"); // <-- this method always returns null
assertThat(user).isEqualTo(expectedUser); // <-- test fails as expectedUser != null
}
}
Also, note that System.out.println is never printed. How to fix this to actually make a call to dao.readByUserid() ?
If you need to test the method of some class, and inside of it the other method of the same class is called which you want to mock, then you need to use #Spy:
#RunWith(MockitoJUnitRunner.class)
public class UserDAO2Test {
#InjectMocks
#Spy
private UserDAO2 dao;
#Test
public void testBean() {
Mockito.doReturn(null).when(dao).getConnFromPool(1);
User expectedUser = new User();
expectedUser.setSk(1);
expectedUser.setFirstName("David");
expectedUser.setLastName("Gahan");
expectedUser.setUserid("user1");
User user = dao.readByUserid("user1");
assertThat(user).isEqualTo(expectedUser);
}
}
Note that I slightly modified the line with mocking getConnFromPool because it's required when you use that technique.
See docs for spying.
I have just started with testing and I'm also using MVP pattern in my android apps.
Currently I have a presenter which uses the following android code to test if an email address is valid :
android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches()
Since it's not possible to test it with a local JVM unit test I decided to hide it behind an interface :
public interface EmailValidator {
boolean isValidEmail(CharSequence target);
}
and here's the implementation :
public class EmailValidatorImpl implements EmailValidator {
#Override
public boolean isValidEmail(CharSequence target) {
if (target == null) {
return false;
} else {
return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
}
}
So now my test code is :
public class SignUpPresenterTest {
#Mock
private SignUpMVP.View view;
#Mock
private EmailValidator validator;
private SignUpPresenter presenter;
private String email = "name#gmail.com";
private String password = "ABCDabcd";
private String username = "username";
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
presenter = new SignUpPresenter(view);
}
#Test
public void onButtonSignUpClicked() throws Exception {
when(validator.isValidEmail(email))
.thenReturn(true);
presenter.onButtonSignUpClicked(email, password, username);
verify(view).executeSignUpService();
}
}
and now I'm getting a NPE when the code above calls : EmailValidatorImpl.isValidEmail()
java.lang.NullPointerException
at com.example.signup.helpers.EmailValidatorImpl.isValidEmail(EmailValidatorImpl.java:20)
at com.example.signup.SignUpPresenter.showErrors(SignUpPresenter.java:67)
at com.example.signup.SignUpPresenter.onButtonSignUpClicked(SignUpPresenter.java:25)
at com.example.signup.SignUpPresenterTest.onButtonSignUpClicked(SignUpPresenterTest.java:43)
and my questions are : isn't this how I Should use Mockito ? Is there anything I can do to test my code and avoid NPE ?
That happens because you are mocking the EmailValidator but you are not using that object inside SignUpPresenter.
You should pass the reference in the constructor:
presenter = new SignUpPresenter(view, validator);
or in the method signature:
presenter.onButtonSignUpClicked(email, password, username, validator);
Then you presenter should be something like this:
public class SignUpPresenter {
private View view;
private EmailValidator validator;
public SignUpPresenter(View view, EmailValidator validator) {
this.view = view;
this.validator = validator;
}
private void onButtonSignUpClicked(String email, String password, String username) {
//Your code...
boolean isValid = validator.isValidEmail(email);
}
}
You should try with this, because you need to provide a real implementation of your interface
#InjectMocks
private EmailValidator validator = new EmailValidatorImpl();
Here is my SendEmail class that I am trying to unit test. I am getting a NullPointerException on the line shown below, but I don't know why.
Also, am I organizing the code properly? I don't exactly know if I am using mockito correctly.
public class StatsTest extends AbstractTestCase {
#Mock
MultiPartEmail MultiPartEmailMock;
StatsTest statsTestObj;
SendEmail mockedEmail;
#Before
public void setUp() throws Throwable {
super.setUp();
MockitoAnnotations.initMocks(this);
}
#Test(expected = ValidationException.class)
public void testSendEmail() throws EmailException, IOException {
MultiPartEmail multiPartEmailMock;
SendEmail mockedEmail = Mockito.mock(SendEmail.class);
Mockito.when((mockedEmail.getHtmlEmail()).send())
.thenThrow(new ValidationException("Could not send the Email."));
^^ the line above is where the null pointer error is
mockedEmail.sendEmail();
}
}
Here is the class under test:
public class SendEmail {
private StringBuilder emailBody;
private String senderEmail;
private ArrayList<String> receiversEmails;
private String emailSubject;
private String hostName;
private MultiPartEmail htmlEmail;
public SendEmail(StringBuilder emailBody, String senderEmail, ArrayList<String>
receiversEmails, String emailSubject, String hostName, MultiPartEmail htmlEmail) {
this.setEmailBody(emailBody);
this.setSenderEmail(senderEmail);
this.setReceiversEmails(receiversEmails);
this.setEmailSubject(emailSubject);
this.setHostName(hostName);
this.setHtmlEmail(htmlEmail);
}
public void sendEmail()throws IOException, EmailException{
htmlEmail.setHostName(getHostName());
htmlEmail.addTo(getReceiversEmails().get(0));
for(int i=0; i<getReceiversEmails().size(); i++){
htmlEmail.addCc(getReceiversEmails().get(i));
}
htmlEmail.setFrom(getSenderEmail());
htmlEmail.setSubject(getEmailSubject());
htmlEmail.setMsg((getEmailBody()).toString());
htmlEmail.send();
}
}
I think you are a bit confused on what you need to be testing and mocking. Mockito offers different ways to create mock object, for example: #Mock or Mockito.mock(). There are also different ways to inject those mock objects into the class under test in order to unit test methods on that class.
Without all the details of the exception or other classes, this will not be a complete answer, but I hope it helps clear up some of the concepts.
Note: the following might not compile, but hopefully you'll get the idea.
public class StatsTest extends AbstractTestCase {
#Mock MultiPartEmail mockMultiPartEmail; // this mock will be used in the instantiaion of the class under test
SendEmail sendEmail; // renamed as this is not a mock, it is the class under test
// define some things we can make assertions against (probably in some other tests...)
private static final StringBuilder BODY = new StringBuilder("body");
private static final String SENDER = "sender#foo.com";
private static final Collection<String> RECIPIENTS = Arrays.asList("recepient#foo.com")
private static final String SUBJECT = "subject";
private static final String HOSTNAME = "hostname";
#Before
public void setUp() throws Throwable {
super.setUp();
MockitoAnnotations.initMocks(this); // will instantiate "mockMultiPartEmail"
// instantiate our class under test
sendEmail = new SendEmail(BODY, SENDER, RECIPIENTS, SUBJECT, HOSTNAME, mockMultiPartEmail);
}
#Test(expected = ValidationException.class)
public void testSendEmail() throws EmailException, IOException {
// given some condition
Mockito.when(mockMultiPartEmail.send()).thenThrow(new ValidationException("Could not send the Email."));
// when the method under test is called
sendEmail.sendEmail();
// then the exception will be thrown (and you have correctly expected this on the #Test annotation)
}
}