2011-12-14 3 views
19

У меня есть строитель:Как издеваются строитель с Mockito

class Builder{ 
    private String name; 
    private String address; 
    public Builder setName(String name){ 
     this.name = name; 
     return this; 
    } 
    public Builder setAddress(String address){ 
     this.address = address; 
     return this; 
    } 

} 

насмешливый строитель в Mockito воли дает мне нуль для каждого метода. Таким образом, есть простой способ заставить построителя возвратиться к каждому вызову функции, не издеваясь над каждой функцией, используя when().thenReturn.

+2

Вам действительно нужно издеваться над этим? Это не похоже на зависимость, которая стоит насмехаться. Это похоже на «данные» типа класса, а не класса «службы». Я редко нахожу, что полезно создавать классы, где не так много фактического поведения. –

+1

Его просто пример, настоящий строитель немного сложнее, и в этом случае просто не нужно тестировать. –

+1

Можете ли вы разделить их так, чтобы у вас * был «немой строитель» (который не нуждается в насмешке), а затем часть обслуживания, которая * * нуждается в насмешке? –

ответ

8

Вы можете использовать RETURN_DEEP_STUBS для измельчения API цепочки.

Если вы знаете точный порядок ваш строитель будет называться, вот пример того, как вы могли бы использовать:

Builder b = Mockito.mock(Builder.class, RETURNS_DEEP_STUBS); 
when(b.setName("a name").setAddress("an address")).thenReturn(b); 
assert b.setName("a name").setAddress("an address") == b; // this passes 

К сожалению, это не даст вам общий способ насмешливый «все различные строитель методы ", чтобы они всегда возвращали это, см. другой ответ - вам это нужно.

+2

Также обратите внимание на то, что если вы получите глубокий порядок заглушки «неправильный» и произведете результат, он даст вам несколько нечетных поисковых сообщений, возможно, например, 'java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer $ ClassWithSuperclassToWorkAroundCglibBug $$ EnhancerByMockitoWithCGLIB $$ 851828bd не может быть добавлен в ... ' – rogerdpack

34

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

import static org.mockito.Mockito.RETURNS_DEFAULTS; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class SelfReturningAnswer implements Answer<Object>{ 

    public Object answer(InvocationOnMock invocation) throws Throwable { 
     Object mock = invocation.getMock(); 
     if(invocation.getMethod().getReturnType().isInstance(mock)){ 
      return mock; 
     } 
     else{ 
      return RETURNS_DEFAULTS.answer(invocation); 
     } 
    } 
} 

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

Создайте свой макет, как этот

Builder mockBuilder = mock(Builder.class, new SelfReturningAnswer()); 

или создать константу для этого класса и написать что-то вроде

@Mock(answer = SELF_RETURNING) private Builder mockBuilder; 

Надежда, что помогает.

+0

Вы уверены. Я использую'verify 'на моем глубоком stubbed mock, и он проходит тесты. Поэтому он должен возвращать один и тот же экземпляр каждый раз, когда я использую метод построения. –

+1

Да, я абсолютно уверен.Я написал тест для вашего класса Builder, как и выше, где я сделал макет с RETURNS_DEEP_STUBS, а затем вызвал setAddress и setName. Мой тест утверждал, что два mocks, возвращенные из двух вызовов метода, были разными. Мой тест прошел. –

+0

Мой тест находится на http://pastebin.com/JNPrn4ng –

12

Начиная с версии Mockito 2.0 (бета-версия), для RETURNS_SELF существует новый ответ по умолчанию, который ведет себя почти идентично David Wallace's answer. Пример из документации Mockito:

@Test 
public void use_full_builder_with_terminating_method() { 
    HttpBuilder builder = mock(HttpBuilder.class, RETURNS_SELF); 
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder); 
    String response = "StatusCode: 200"; 

    when(builder.request()).thenReturn(response); 

    assertThat(requester.request("URI")).isEqualTo(response); 
} 

Обратите внимание, что она появляется и на Mockito классе и на Answers перечислении, поэтому он также совместим с @Mock(answer = RETURNS_SELF) синтаксиса.

Смежные вопросы