【问题标题】:Mocking twilio with mockito用 mockito 模拟 twilio
【发布时间】:2013-06-11 17:15:18
【问题描述】:

我正在为一个方法编写单元测试,如果在我的 twilio 帐户中已经找到子帐户,该方法返回 true。我正在尝试使用 Mockito 来模拟它,但在将 List 转换为 AccountList 时出现转换错误。我查看了 mockito 文档,但可能遗漏了一些东西。

这是测试:

        @Mock
TwilioRestClient client;

@Mock
AccountList accountList;

@Mock
Iterator<Account> iterator;

@Mock
Account account;

@Test
public void testShouldReturnTrueIfAccountNameFound() {
        final List<Account> list = Arrays.asList(account);

        when(client.getAccounts()).thenReturn((AccountList) list);
        when(account.getFriendlyName()).thenReturn("test");
        when(accountList.iterator()).thenReturn(list.iterator());
    MyTwilioAccountStore store = null;
    store = new MyTwilioAccountStore(client);

    Assert.assertTrue(store.subAccountExists("test"));  
}

这就是我正在测试的方法。我在构造函数中注入了 TwilioRestClient。

        /**
 * class constructor
 * 
 * @param client
 */
public MyTwilioAccountStore(TwilioRestClient client) {
    fClient = client;
}


/**
 * rest client getter
 * 
 * @return RESTClient
 */
public TwilioRestClient getRestClient() {
    return fClient;
}
     /**
 * Check if a sub account already exists
 * 
 * @param friendlyName
 * @return boolean
 */
public boolean subAccountExists(String friendlyName) {
    // Build a filter for the AccountList
    Map<String, String> params = new HashMap<String, String>();
    params.put("FriendlyName", friendlyName);
    AccountList accounts = getRestClient().getAccounts(params);

    // Loop over accounts
            // This is where I get NPE
    for (Account account : accounts) {
        if (account.getFriendlyName().equalsIgnoreCase(friendlyName)) {
            return true;
        }
    }

    return false;
}

这是 Twilio 源代码的 getAccounts:

    /**
 * Get all accounts. For more info: {@link <a
 * href="http://www.twilio.com/docs/api/rest/account"
 * >http://www.twilio.com/docs/api/rest/account</a>}
 *
 * @return the list of accounts.
 */
public AccountList getAccounts() {
    return this.getAccounts(new HashMap<String, String>());
}

如何正确模拟 AccountList?

【问题讨论】:

  • 你从哪里得到你的 NPE?
  • 对不起,但你必须澄清一下,在这种情况下 NPE 是什么?
  • 看来客户端在某处有.getAccounts(Map&lt;String, String&gt;()) 方法,对吗?这个方法的访问修饰符是什么?
  • 你能展示一下AccountList的原型,或者至少提供一个链接吗?
  • 当然,这里是 AccountList 的来源,在这里发布有点长。 github.com/twilio/twilio-java/blob/master/src/main/java/com/…

标签: java oop unit-testing mockito twilio


【解决方案1】:

在我看来,你做错了。仅仅因为你在一个字段上说@Mock,并不意味着任何实例化相同类型的类的东西都会得到它。您需要找到一种方法让 getRestClient() 返回 your 模拟。如果它返回一个new AccountList,那将不是你的模拟,它可能会导致这些问题。

向我们展示getRestClient() 方法,我可以提供更多帮助。


好的,你有一个 getAccounts() 方法,你正在用这一行模拟:

    when(client.getAccounts()).thenReturn((AccountList) list);

但是被测系统调用了这一行:

    AccountList accounts = getRestClient().getAccounts(params);

看到这里的区别了吗?被调用的实际方法采用Map,但您不是在模拟该方法。您需要将上述时间更改为以下内容:

    when(client.getAccounts(any(Map.class))).thenReturn((AccountList) list);

换句话说,你在嘲笑错误的方法。默认情况下,Mockito 将返回合理的默认值,在这种情况下,恰好是 null。如果getAccounts() 返回一个 Integer/int,它将返回 0。

【讨论】:

  • getRestClient 只是变量 client 的 getter,它在构造函数中设置为注入的 TwilioRestClient 的值。
  • @Phil 编辑您的原始问题以向我们展示。我需要查看 NullPointerException,我需要查看它发生在哪一行,我需要查看 getAccounts() 是如何工作的。信息不足。
  • 更新了问题。在 NPE 发生的地方添加了一条评论,即账户被迭代的时候。感谢您的帮助
  • @Phil 这是一个错字。使用any(Map.class)
  • @Phil 如果你 import static org.mockito.Mockito.*; 它会提供给你
【解决方案2】:

编辑看来这里真正的问题是能够模拟从 twilio 客户端返回的 AccountList...

编辑继续如果我怀疑这个类实现了Iterable&lt;Account&gt;,那么需要使用模拟Account 构建单个元素列表,并让accountList.iterator() 返回一个上面创建的列表的Iterator


原答案

你嘲笑:

when(accountList.iterator().next())

但是,当您使用 foreach 循环时,首先调用的是 .iterator() 本身——而您对此没有任何模拟。作为返回,mockito 执行默认操作:返回 null(老实说,我真的很惊讶它甚至没有在这里抛出异常告诉“抱歉,不能这样做”,因为它是一个链式方法调用!)。

你应该:

when(accountList.iterator()).thenReturn(anIterator);

其中anIterator 是一个实际的迭代器,包含.hasNext().next().remove()

由于您似乎也想为您的帐户使用模拟,我想您的列表应该这样设置:

final List<Account> accountList = Arrays.asList(account);

这给出了:

@Test
public void shouldReturnTrueIfAccountNameFound() 
{
    final List<Account> list = Arrays.asList(account);

    when(account.getFriendlyName()).thenReturn("test");
    when(accountList.iterator()).thenReturn(list.iterator());

    final MyTwilioAccountStore store = new MyTwilioAccountStore(client);

    Assert.assertTrue(store.subAccountExists("test"));  
}

【讨论】:

  • 嗯,我试试这个。我用我的尝试的更新版本编辑了我的问题。它仍然给出一个 NPE。如果可能的话,我会尝试这种方法。 List 可能无法转换为 AccountList。给我一点时间。
  • 不是这样的!从您的代码中我看到AccountList 实现了Iterable&lt;Account&gt;,我说的不对吗?
  • 尝试了您的方法,但仍然获得了 NPE。奇怪的。我更新了我的问题以反映它的外观。
  • 好的,那么你需要让你的client返回.getAccounts()上的实际列表...
  • 是的,我这样做给我的演员阵容带来了问题。是嘲讽到这里的路吗?谢谢你的帮助,真的。
猜你喜欢
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 2020-11-29
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
相关资源
最近更新 更多