Here is my first class where the constructor has an object calling methods in other class.
Class Search{
public Search(String username, JSONObject accounts) throws Exception {
Credentials credentials = new Credentials(username);
String Uid = credentials.getUserName();
String Pwd = new String(credentials.getCredentials().getPassword());
}
public getDOB(){
--------------------
-------------
}
}
Class Credentaials:
import javax.resource.spi.security.PasswordCredential;
Public class Credentials{
public Credentials(String name){
}
public PasswordCredential getCredentials(){
return passwordCredential;
}
public String getUserName(){
PasswordCredential localCredential = getCredentials();
return localCredential.getUsername();
}
}
Class test:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Search.class, Credentials.class})
public class JunitTest {
@Test
public void playTest() {
PasswordCredential pwdCreds = new PasswordCredential();
pwdCreds.setPassword("test");
Credentials credentials = new Credentials("user");
Credentials credentials = Mockito.spy(credentials);
Mockito.doReturn(pwdCreds).when(credentials).getCredentials();
Mockito.doReturn("cmApptest").when(credentials).getUserName();
Search search = new Search("username", jsonobject);
search.getDOB();
}
}
Whenever I debug the test class, it is executing the getCredentials
and getUserName
methods even after I mocked them. I was expecting the actual methods not to execute, instead it should return the values as I mentioned in the JunitTest class.
You aren't replacing the real version of Credentials that is being used in your Search class with a mock. Rather, you're clearly creating and using a real Credentials object inside of your Search object's constructor. For mocking to work, you have to actually replace the credentials object in your Search object with a mock. Just creating a mock of the same type somewhere in your code doesn't cause it to replace instances of the real object somewhere else in your code.
Often, dependency injection is used to introduce mocking, like with Spring. Here's a simple way to do what you want. Redefine your Search constructor like this:
class Search {
Search(String username, JSONObject accounts, Credentials creds) throws Exception {
Credentials credentials = creds? creds : new Credentials(username);
String Uid = credentials.getUserName();
String Pwd = new String(credentials.getCredentials().getPassword());
}
Search(String username, JSONObject accounts) throws Exception {
this(username, accounts, null);
}
}
The behavior of your production code will not be affected, but you can optionally construct Search with a mock.
Credentials credentials = new Credentials("user");
Credentials credentials1 = Mockito.spy(credentials);
Mockito.doReturn(pwdCreds).when(credentials1).getCredentials();
Mockito.doReturn("cmApptest").when(credentials1).getUserName();
Search search = new Search("username", jsonobject, credentials1);
search.getDOB();
There's no magic in terms of your code using a mock rather than the real object. Mocking frameworks just let you easily create stand-in objects that act in very specific ways for testing. You still have to cause those objects to be used by your code.
Also, you don't really need/want a spy here. You really want a mock, because you're defining the behavior of all of the methods in Credentials. With a mock, you wouldn't need to instantiate your Credentials object at all. So the first lines of the test code I gave above could could be:
Credentials credentials1 = Mockito.mock(Credentials.class);
(or something like this. I'm not actually trying this code)