无法模拟构造函数中的方法

Can't mock the methods inside the constructor

这是我的第一个 class,构造函数在其他 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 证书:

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 测试:

@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();

      }

}

每当我调试测试 class 时,即使我模拟了它们,它也会执行 getCredentialsgetUserName 方法。我期待实际的方法不会执行,相反它应该 return 我在 JunitTest class.

中提到的值

您并未将搜索 class 中使用的凭据的真实版本替换为模拟。相反,您显然是在 Search 对象的构造函数中创建和使用真实的 Credentials 对象。要使模拟工作,您必须实际用模拟替换搜索对象中的 credentials 对象。只是在代码中的某处创建相同类型的模拟不会导致它替换代码中其他地方的真实对象的实例。

通常,依赖注入用于引入模拟,例如 Spring。这是一个简单的方法来做你想做的事。像这样重新定义您的搜索构造函数:

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);
    }
}

您的生产代码的行为不会受到影响,但您可以选择使用 mock 构造 Search。

    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();

就您的代码而言,使用模拟对象而不是真实对象并没有什么神奇之处。模拟框架只是让您轻松创建以非常特定的方式进行测试的替代对象。您仍然需要让您的代码使用这些对象。

此外,您并不是真正的 need/want 间谍。您确实需要一个 mock,因为您正在定义 Credentials 中所有方法的行为。使用 mock,您根本不需要实例化您的 Credentials 对象。所以我上面给出的测试代码的第一行可能是:

Credentials credentials1 = Mockito.mock(Credentials.class);

(或类似的东西。我实际上并没有尝试这段代码)