2014-10-17 6 views
2

Я пытаюсь проверить свою реализацию с помощью jUnit и Mockito, и у меня проблемы. Вот очень упрощенный пример, который объясняет этот вопросMocking getter/setter метод интерфейса с Mockito

Интерфейс KeyValueInterface

public interface KeyValueInterface { 

    public abstract String getKey(); 

    public abstract void setKey(String key); 

    public abstract String getValue(); 

    public abstract void setValue(String value); 

} 

Класс KeyValueImpl

public class KeyValueImpl implements KeyValueInterface { 

    private String key; 
    private String value; 

    @Override 
    public String getKey() { 
     return key; 
    } 

    @Override 
    public void setKey(String key) { 
     this.key = key; 
    } 

    @Override 
    public String getValue() { 
     return value; 
    } 

    @Override 
    public void setValue(String value) { 
     this.value = value; 
    } 

} 

класса с "бизнес-логики"

public class ValueFinder { 

    public KeyValueInterface findValueForKey(KeyValueInterface keyValue){ 
     keyValue.setValue("foo"); 
     return keyValue; 
    } 

} 

JUnit Test класса

import static org.junit.Assert.*; 

import org.junit.Test; 
import org.mockito.Mockito; 

public class ValueFinderTest { 

    @Test 
    public void testNotMocked() { 
     KeyValueInterface keyValue = new KeyValueImpl(); 
     keyValue = (new ValueFinder()).findValueForKey(keyValue); 
     assertEquals("foo", keyValue.getValue()); // works fine 
    } 

    @Test 
    public void testMocked1() { 
     KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class); 
     keyValue = (new ValueFinder()).findValueForKey(keyValue); 
     assertEquals("foo", keyValue.getValue()); // java.lang.AssertionError: 
                // expected:<foo> but 
                // was:<null> 

    } 

    @Test 
    public void testMocked2() { 
     KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class); 
     keyValue = (new ValueFinder()).findValueForKey(keyValue); 
     Mockito.when(keyValue.getValue()).thenCallRealMethod(); 
     Mockito.doCallRealMethod().when(keyValue).setValue(Mockito.any(String.class)); 
     assertEquals("foo", keyValue.getValue()); // org.mockito.exceptions.base.MockitoException: 
                // Cannot call real method 
                // on java interface. 
                // Interface does not have 
                // any implementation! 
                // Calling real methods is 
                // only possible when 
                // mocking concrete classes. 

    } 

} 

Моим вопросом является то, что мне нужно высмеять KeyValue по техническим причинам, которые не поддаются контролю. Поэтому я не могу просто пойти с методом testNotMocked(). Кроме того, по техническим причинам, не зависящим от меня, я должен издеваться над интерфейсом (а не с классом).

Есть ли способ достичь этого?

Большое спасибо.

ответ

2

Если вы должны были написать Javadoc метода, который вы тестируете, даже не зная, что любой из методов интерфейса делают, можно было бы написать следующее:

/** 
* Sets "foo" as the value of the given keyValue, and returns it 
*/ 

Вы не должны даже предположим, что getValue() возвращает значение, которое было установлено ранее. Это, конечно, не то, что макет будет делать, так как макет не делает ничего, кроме того, что вы говорите ему. Все, что вам нужно сделать, это проверить контракт вашего метода, не предполагая ничего о реализации интерфейса. Так что ваш тест должен быть

@Test 
public void testMocked1() { 
    KeyValueInterface keyValue = Mockito.mock(KeyValueInterface.class); 
    KeyValueInterface result = (new ValueFinder()).findValueForKey(keyValue); 

    // tests that the value has been set to "foo" 
    verify(keyValue).setValue("foo"); 

    // tests that the method returns its argument 
    assertSame(keyValue, result); 
} 
1

Mock ничего не знает о вашем классе Impl. Итак, просто сделайте verify для setValue или используйте шпион для вызова real методов.

0

если вы проверяете API Mockito для фиктивного метода ниже вы можете увидеть, что он создает ложный объект данного класса или интерфейса.

public static <T> T mock(java.lang.Class<T> classToMock) 

Таким образом, ошибка для первого метода testMocked1() является допустимой. то, что вы на самом деле делаете, издевается над этим интерфейсом косвенно. Поэтому, когда вы делаете это, все методы обманываются, и поскольку getValue() возвращает String, значение по умолчанию String равно null, поэтому возвращается NULL. Используйте ReflectionUtils, как показано ниже, чтобы установить значение ключа непосредственно

ReflectionTestUtils.setField(classObject, key,keyvalue); 

и сделать ниже в методе testMocked1()

assertEquals("foo", keyValue.getValue()); 

Аналогично для 2-го метода testMocked2() делать то же самое с помощью reflectionutils для установки значения и использовать любой из методов api от Mockito

+0

Спасибо, вы имеете в виду ReflectionTestUtils из весеннего каркаса? – Paul

+0

да, но общая идея должна быть одинаковой везде – vikeng21

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