2015-02-10 2 views
2

Я пытаюсь установить тестовый код, который использует com.basho.riak: riak-client: 2.0.0. Я высмеял все клиентские классы riak и надеялся получить бесполезный, но рабочий тест. Тем не менее, это не удается с нулевым указателем:Как насмехаться с клиентом riak java?

java.lang.NullPointerException 
    at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243) 
    at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150) 
    at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171) 

Мой тест выглядит следующим образом:

@Test public void test() {   
     RiakClient riakClient = mock(RiakClient.class); 

     @SuppressWarnings("unchecked") 
     RiakCommand<FetchValue.Response, Location> riakCommand = (RiakCommand<FetchValue.Response, Location>) mock(RiakCommand.class); 

     Response response = mock(Response.class); 
     when(riakClient.execute(riakCommand)).thenReturn(response); 
     Response returnedResponse = riakClient.execute(riakCommand); 

     when(response.getValue(Object.class)).thenReturn(new Object()); 
     MyPojo myData = returnedResponse.getValue(MyPojo.class); 
     // Make assertions 
    } 

Как вы модульного тестирования кода, который использует клиент Riak? В конце концов, я хотел бы убедиться, что используется ожидаемая комбинация типа/bucket/key и что ожидаемый RiakCommand запускается.

EDIT: Я вырыл больше в FetchValue класс и нашел эту структуру:
FetchValue - это public final

FetchValue.Response
- это public static,
- имеет пакет частно-конструктор Response(Init<?> builder)

FetchValue.Response.Init<T>:
- protected static abstract class Init<T extends Init<T>> extends KvResponseBase.Init<T>

И есть FetchValue.Response.Builder:
static class Builder extends Init<Builder>
- со встроенным(), что: return new Response(this);

Я предполагаю, что Mockito получает где-то затерялся среди внутренних классов и мой призыв заканчивается в KvResponseBase.convertValues, где NP отбрасывается , KvResponseBase.convertValues принимает значения List<RiakObject> и я не вижу разумного способа его присвоения.

ответ

1

Я немного расследовал ваш случай.У меня есть уменьшить пример этой простой SSCCE:

import static org.mockito.BDDMockito.given; 
import static org.mockito.Mockito.mock; 
import org.junit.Test; 
import com.basho.riak.client.api.commands.kv.FetchValue.Response; 

public class RiakTest { 
    @Test 
    public void test() throws Exception { 
     Response response = mock(Response.class); 
     given(response.getValue(Object.class)).willReturn(new Object()); 
    } 
} 

который бросает эту ошибку:

java.lang.NullPointerException 
at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243) 
at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150) 
at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171) 
at RiakTest.test(RiakTest.java:12) 

После некоторого копания, я думаю, что я бы определил эту проблему. Это то, что вы пытается окурок открытого метода, который наследуется из пакета (видимость) класс:

abstract class KvResponseBase { 
    public <T> T getValue(Class<T> clazz) { 
    } 
} 

Кажется, что Mockito не удается окурок этого метода таким образом, реальный один вызывается и NullPointerException является (из-за доступа нулевого члена: values). Одна важная вещь, чтобы отметить, что если вызов функции не удается, Mockito покажет правильную ошибку:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
    when() requires an argument which has to be 'a method call on a mock'. 
    For example: 
     when(mock.getArticles()).thenReturn(articles); 

    Also, this error might show up because: 
    1. you stub either of: final/private/equals()/hashCode() methods. 
     Those methods *cannot* be stubbed/verified. 
     Mocking methods declared on non-public parent classes is not supported. 
    2. inside when() you don't call method on mock but on some other object. 

Я предполагаю, что это ошибка Mockito или ограничение так что я открыть вопрос в Mockito tracker где я воспроизвожу ваш случай с помощью простых классов.


UPDATE

The issue i opened фактически дубликатом existing one. Эта проблема не будет исправлена, но обходной путь существует. Вы можете использовать mockmaker Bytebuddy вместо cglib one. Explanations можно найти здесь.

+0

Принято. Ваши результаты вокруг Мокито действительно впечатляют. Вы помогли мне понять, что Mockito - не идеальный инструмент для этой задачи. Теперь, когда вы устарели от кода riakClient, есть ли у вас какие-либо предложения по тестированию кода, который его использует? Благодаря! – Mrtn

+0

@Mrtn рада помочь. Я думаю, вы должны задать новый вопрос, подвергая очистке то, что вы пытаетесь проверить. Я думаю, что вы получите более широкую помощь, поскольку она не связана с тестированием mockito, а с (unit) в целом.И даже если я немного посмотрю на некоторые классы в Riak, я из эксперта;) – gontard

0

Вы не можете высмеивать final классы и final и/или static методы с mockito. Обратите внимание: static вложенные классы в порядке. Это связано с тем, что подклассы mockito (я не на 100% уверен, что это точная операция, он использует CGLIB для генерации классов), но не может переопределять конечные методы или расширять конечные классы. Для методов static невозможность переопределения невозможна.

В вашем коде вы, вероятно, пытаетесь назвать последний класс или метод. Трудно сказать, какой класс вызывает проблему, из вашего стоп-кадра NullPointer вы должны заподозрить первый объект на нем, который вы издевались (начиная с метода testcase). Метод на макете не должен вызывать какие-либо другие методы (ожидать внутреннего для mockito), поэтому, вероятно, это окончательно, потому что вы, похоже, не называете метод «mocked».

В вашем случае stacktrace не является полным (поскольку ваш тестовый файл не находится на нем). Вкратце взглянув на рамки riak, я не смог найти способ взглянуть на FetchValue$Response.getValue.

Также обратите внимание на следующее. Из опубликованного фрагмента я не могу сказать, что вы тестируете в своей тестовой папке. Все объекты, которые вы создаете, являются издевательскими. Обычно у вас есть 1 (или несколько) реальных классов, которые вы тестируете. Другие классы (которые взаимодействуют с тестируемыми вами классами) вы издеваетесь над тем, чтобы имитировать сложное поведение.

+0

Я согласен с большей частью вашего ответа и особенно с последним абзацем: * Что такое Цель этого теста *? Но я должен сказать, что ** ваш диагноз неправильный **, я сделал основной шаг над его проектом, а классы/методы не являются окончательными, а методы не являются статическими. Я еще не нашел проблему. – gontard

+0

Согласен, этот тест бессмыслен. Мой великий план состоял в том, чтобы утверждать, что мое приложение передало ожидаемые аргументы RiakClient. Смысл и сопоставление аргументов, казалось, были способом. Теперь, благодаря @gontard, мы знаем больше, и мне нужно найти другое решение. Спасибо за внимание и время! – Mrtn

0

Развейте: Благодаря @gontard я смог найти это:

<dependency> 
    <!-- We need this fix: https://github.com/mockito/mockito/pull/171 to use mockito with Riak --> 
<!--http://stackoverflow.com/questions/28442495/how-to-mock-riak-java-client#28474106--> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId> 
    <version>2.0.52-beta</version> 
    <scope>test</scope> 
    </dependency> 

То есть исправления включены.

К сожалению, если вы используете как Fetch, так и MultiFetch (скорее всего), вы находитесь в ручье.

MultiFetch.Response является конечным классом (так что вы можете использовать Mockito, вам нужно использовать PowerMock) FetchValue.Response имеет проблемы вы описанные, и может быть устранен только с бетой Mockito, не доступен с powermock еще. ..

Update, я понял, как использовать оба Mockito & powermock вместе (до обновления powermock):

<!-- We need this to mock Multi-Fetch responses from Riak, which are final --> 
<!-- However, we need the beta version of mockito due to bugs (see below), 
so we _cannot_ use the mockito api provided by powermock, do _not_ include _powermock-api-mockito, it'll mess stuff up --> 
<dependency> 
    <groupId>org.powermock</groupId> 
    <artifactId>powermock-module-junit4</artifactId> 
    <version>1.6.4</version> 
    <scope>test</scope> 
</dependency> 
<!--If we don't include this, we get: --> 
<!--java.lang.IllegalStateException: 
Extension API internal error: org.powermock.api.extension.proxyframework.ProxyFrameworkImpl could not be located in classpath.--> 
<!-- it looks like this is due to some discrepancy in packaging with mockito 2, this may be fixed in Fall 2016: 
https://groups.google.com/forum/#!topic/powermock/cE4T40Xa_wc --> 
<dependency> 
    <groupId>org.powermock</groupId> 
    <artifactId>powermock-api-easymock</artifactId> 
    <version>1.6.4</version> 
</dependency> 


<!-- We need this fix: https://github.com/mockito/mockito/pull/171 to use mockito with Riak --> 
<!--http://stackoverflow.com/questions/28442495/how-to-mock-riak-java-client#28474106--> 
<dependency> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId> 
    <version>2.0.52-beta</version> 
    <scope>test</scope> 
    </dependency> 
Смежные вопросы