【问题标题】:Can't mock the methods inside the constructor无法模拟构造函数中的方法
【发布时间】:2019-03-21 23:35:31
【问题描述】:

这是我的第一个类,其中构造函数有一个对象调用其他类中的方法。

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(){
 --------------------
 -------------
}
}   

班级证书:

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

类测试:

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

      }

}

每当我调试测试类时,它都会执行getCredentials 和getUserName 方法,即使在我模拟它们之后也是如此。我期待实际的方法不会执行,而是应该返回我在 JunitTest 类中提到的值。

【问题讨论】:

  • 此代码无法编译。您定义了 credentials 两次。您永远不会使用 person1。 pwdCreds 在哪里定义?我没有做过很多模拟,但你为什么使用跑步者 PowerMockRunner.class 却使用 Mockito?也许没关系,但作为一个嘲弄的新手,这对我来说似乎不匹配。
  • 刚才我已经编辑过,现在您看到的是正确的副本。
  • @蝙蝠侠:不是这样;你仍然声明credentials 两次,这是一个编译错误。

标签: java mockito junit4 powermockito


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

  • 为什么?我只是传达一个想法。我知道非模拟特定部分会起作用,这传达了他所遇到问题的解决方案,而且我没有让模拟代码变得更糟。我不想建立 Mockito 和一个围绕它构建的项目,只是为了帮助这个人了解他正在努力解决的基本想法。他只需要明白要使用模拟,他必须使用模拟。 @FailingCoder,您为什么不通过运行此代码来提供帮助并让我们都知道是否需要进行更多更改?
  • [我的意思是如果蝙蝠侠想用它自己测试一下……抱歉造成误解,而且我没有 javafx 库]
  • Doh!...对不起@FailingCoder。显然我误解了:( - 我以为你在回复我说我没有测试过代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
  • 2018-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
相关资源
最近更新 更多