-1

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.

Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
Batman
  • 103
  • 3
  • 12
  • 2
    This code won't compile. You're defining **credentials** twice. You're never using **person1**. Where is **pwdCreds** defined? I haven't done a lot of mocking, but why are you using the runner PowerMockRunner.class but then using Mockito? Maybe that's OK, but it seems like a mismatch to me as a mocking novice. – CryptoFool Mar 21 '19 at 23:41
  • just now i've edited and right now you are seeing the correct copy. – Batman Mar 21 '19 at 23:59
  • @Batman: Not so; you're still declaring `credentials` twice, which is a compile-error. – ruakh Mar 22 '19 at 00:39

1 Answers1

1

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)

CryptoFool
  • 21,719
  • 5
  • 26
  • 44
  • Why? I'm just conveying an idea. I know that the non-mock-specific parts will work, which is conveying the solution to the problem he's having, and I haven't made the mocking code any worse. I don't want to set up Mockito and a project built around it just to help this guy with the basic idea he's struggling with. He just needs to understand that to use a mock, he has to USE the mock. @FailingCoder, why don't you help out by running this code and letting us all know if more changes have to be made? – CryptoFool Mar 22 '19 at 00:24
  • [I meant if Batman wants to use it test it themself... sorry for the misunderstanding plus I don't have javafx libraries] – FailingCoder Mar 22 '19 at 00:30
  • Doh!...sorry @FailingCoder. I misunderstood, obviously :( - I thought you were responding to me saying I hadn't tested the code. – CryptoFool Mar 22 '19 at 00:33