2015-09-28 2 views
10

Предположим, у меня есть класс с двумя методами, где я не волнует, что называется ...Как я могу проверить, вызван ли один из двух методов с помощью Mockito?

public class Foo { 
    public String getProperty(String key) { 
     return getProperty(key, null); 
    } 
    public String getProperty(String key, String defaultValue) { 
     //... 
    } 
} 

И ниже (от другого класса, до сих пор в моем приложении) должны пройти мой тест:

public void thisShouldPass(String key) { 
    // ... 
    String theValue = foo.getProperty(key, "blah"); 
    // ... 
} 

public void thisShouldAlsoPass(String key) { 
    // ... 
    String theValue = foo.getProperty(key); 
    if (theValue == null) { 
     theValue = "blah"; 
    } 
    // ... 
} 

Мне все равно, что было вызвано, я просто хочу, чтобы один из двух вариантов был вызван.

В Mockito, я вообще могу сделать что-то вроде этого:

Mockito.verify(foo, atLeastOnce()).getProperty(anyString()); 

Или:

Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString()); 

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

Или я должен сделать что-то, как нефть, как:

try { 
    Mockito.verify(foo, atLeastOnce()).getProperty(anyString()); 
} catch (AssertionError e) { 
    Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString()); 
} 

ответ

4

Вы можете использовать atLeast(0) в сочетании с ArgumentCaptor:

ArgumentCaptor<String> propertyKeyCaptor = ArgumentCaptor.forClass(String.class); 
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor.capture(), anyString()); 

ArgumentCaptor<String> propertyKeyCaptor2 = ArgumentCaptor.forClass(String.class); 
Mockito.verify(foo, atLeast(0)).getProperty(propertyKeyCaptor2.capture()); 

List<String> propertyKeyValues = propertyKeyCaptor.getAllValues(); 
List<String> propertyKeyValues2 = propertyKeyCaptor2.getAllValues(); 

assertTrue(!propertyKeyValues.isEmpty() || !propertyKeyValues2.isEmpty()); //JUnit assert -- modify for whatever testing framework you're using 
+0

Мне это нравится! Я думал, что аргумент ArgumentCaptor был устаревшим, но на самом деле кажется, что конструктор устарел, ваш метод 'forClass' по-прежнему пользуется преимуществом. Я предполагаю 'atLeast (0)' потому, что вам нужно вызвать 'verify', чтобы прикрепить' ArgumentCaptor'? – Kidburla

+0

Точно верно. Я часто использую 'ArgumentCaptor' для этих типов вещей (хотя это не так), это очень удобно. Пока я не посмотрел его, я даже не знал, что 'atLeast (0)' возможно - в более ранних версиях Mockito этого не было. – ach

+0

Я просто заметил, что 'ArgumentCaptor' не следует использовать с stubbing в соответствии с JavaDoc. Я думаю, что мне, возможно, придется это сделать, поскольку я собираю оба варианта getProperty. Я также смущен, когда в приведенном выше фрагменте мне нужно вызвать 'thisShouldPass' или' thisShouldAlsoPass'. Несомненно, 'ArgumentCaptor' не может быть прикреплен * после * Я запустил эти методы? – Kidburla

1

В вашем конкретном случае, getProperty(String) вызовы getProperty(String, String) внутренне.

public String getProperty(String key) { 
    /* 
    * getProperty(String, String) is called anyway. 
    * Why not simply verify the occurrence of that? 
    */ 
    return getProperty(key, null); 
} 

Просто проверки второй метод будет эквивалентна проверке возникновения либо одного или другого, по крайней мере один раз.

Mockito.verify(foo, atLeastOnce()).getProperty(anyString(), anyString()); 
+1

Привет, Джон - если я высмеиваю класс 'Foo', то, конечно,' getProperty (String) 'не будет вызывать' getProperty (String, String) '- он просто вернет значение из макета (я считаю, пустая строка или null по умолчанию ... не помню)? – Kidburla

+1

Да, ты прав. Один из способов - это «callRealMethod()», когда «getProperty (String)». –

2

Вообще, если вы звоните verify на «добытчика» любого рода, Вы предполагаете слишком много о реализации. Mockito обычно предназначен для гибких тестов (по сравнению с «хрупким» тестом, который необходимо изменить, даже если код правильный); вашему тесту следует больше заботиться о : значение верное, а не , которое использовало методы. Лучшим решением может быть stub оба геттера, чтобы вернуть предсказуемое значение, а затем использовать нормальное утверждение против того же значения, чтобы обеспечить его прохождение в нужное место.

when(mockFoo.getProperty("bar")).thenReturn("bar value"); 
when(mockFoo.getProperty("bar", anyString())).thenReturn("bar value"); 
// ... 
assertEquals("bar value", new SystemUnderTest(mockFoo).getBarProperty()); 

документация Mockito в заклинаниями это:

Хотя можно проверить погасил вызов, как правило, это просто излишним. Допустим, вы зарезали foo.bar(). Если ваш код заботится о том, что foo.bar() возвращает, то что-то еще ломается (часто до того, как будет выполнен даже verify()). Если вашему коду все равно, что возвращает get(0), его не следует зашивать.

Тем не менее, если это шаблон, вы должны поддерживать (или вызов метода с обеими перегрузками и побочными эффектами), вы можете получить много информации по Mockito.mockingDetails и MockingDetails.getInvocations, в том числе вызовов по состоянию на Mockito 1.10.0.Вам нужно будет пройти через объекты Invocation, чтобы проверять несколько методов.

boolean found = false; 
Method method1 = Foo.class.getMethod("getProperty", String.class); 
Method method2 = Foo.class.getMethod("getProperty", String.class, String.class); 
for (Invocation invocation : Mockito.mockingDetails(foo).getInvocations()) { 
    if (method1.equals(invocation.getMethod()) 
     || method2.equals(invocation.getMethod()) { 
    found = true; 
    break; 
    } 
} 
assertTrue("getProperty was not invoked", found); 

Обратите внимание, что это второго решения немного опасно, так как она не приносит пользы от автоматических инструментов рефакторинга, встроенных в Иду, и может быть труднее читать, чем некоторые другие решения. (Вышеупомянутые могут также отсутствовать в адресах isIgnoredForVerification, markVerified и других тонкостях.) Однако, если вы предусмотрите необходимость этого часто на большой базе кода, то использование встроенных API Mockito может позволить вам гораздо большую гибкость, чем в противном случае.

+0

У моего кода есть два пути: один использует 'getProperty', а другой использует Spring. В моих тестах мне нужно проверить, что метод 'getProperty' использовался, а не путь Spring при определенных обстоятельствах, потому что в моем реальном приложении (когда метод вызывается во время инициализации контекста Spring) переменные Spring еще не будут доступны , но они доступны в моем тесте. – Kidburla

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