2014-12-15 2 views
1

Я новичок в модульном тестировании, и я пытаюсь проверить, что метод был вызван. Этот метод ничего не возвращает.JUnit - проверить, что метод был вызван

public void example (boolean foo) { 

    if (foo) { 
     processFoo(foo); 
    } 
    else if (foo==false) { 
     processSomethingElse(foo); 
    } 
} 

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

Если насмехается, то я должен использовать JMockit. Благодаря!

+0

Возможный дубликат [Unit testing and assert case for void method] (http://stackoverflow.com/questions/8230150/unit-testing-and-assert-case-for-void-method) –

+0

Вы можете создать ' spy' класса под тестом, бросая какое-то исключение, когда вызывается метод processFoo. Если вы поймаете это исключение, все будет в порядке, иначе этот метод не был вызван. – bsiamionau

+0

Боковое примечание: 'foo' может быть истинным или ложным. Поэтому ваш код должен быть 'if (foo) {..} else {...}'. –

ответ

0

Вы можете использовать переменную счетчика в своем классе и увеличивать ее каждый раз, когда вызывается метод, или использовать инструкцию печати. Если у вас нет доступа к методу processFoo, простой подход заключается в том, чтобы сделать это в то время, когда processFoo вызывается другим способом, , если это единственное место, где его можно назвать.

Например:

public static int processFooCalls = 0; 
// ... 
public void example (boolean foo) { 
    if (foo) { 
     processFoo(foo); 
     processFooCalls += 1; 
     // and/or 
     System.out.println("processFoo method was called"); 
    } 
    // ... 
} 

public static void main (String[] args) { 
    // main routine here... 
    System.out.println("'processFoo' was called " + processFooCalls + " times."); 
} 

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

void processFoo(boolean b) { 

    // increment number of times processFoo was called here, and/or print, as follows 
    processFooCalls += 1; 
    System.out.println("called processFoo method!"); 

    /* some functionality */ 
} 
+4

Приборный код исключительно для тестирования - это запах; существует какое-то количество насмешливых фреймворков, разработанных специально для проверки поведения, такого как «было ли это называется», «убедитесь, что оно было вызвано n раз [с аргументом x]» и т. д. –

+0

@DaveNewton на основе того факта, что OP упоминает «JMockit», я думаю ваш комментарий применим и должен указывать, что мое решение не является идеальным. Я никогда не использовал насмешливую структуру на любой глубине, и я не знал, о чем говорил [запах] (http://en.wikipedia.org/wiki/Code_smell). (Спасибо!) Tl; dr - Я думаю, что мой ответ работает на тривиальные/мелкомасштабные/контролируемые тестовые среды, но ответ далеко не универсален. –

+0

В дополнение к тому, что сказал @Dave, добавление оператора печати для модульного теста является большим, не-no. Это означает, что вам нужно вручную проверить, прошел ли ваш тест или нет – tddmonkey

0

Глядя на документации JMockit, вам понадобятся следующие инструменты:

Static Mocking: http://jmockit.github.io/tutorial/BehaviorBasedTesting.html#staticPartial

Призыва Графы: http://jmockit.github.io/tutorial/BehaviorBasedTesting.html#constraints

Объединяя два в тесте (мой синтаксис может быть немного не так как я больше привык к Mockito, но концепция должна держать):

@Test 
public void someTestMethod(@Mocked({"processFoo"}) final ExampleClass exampleclass) 
{ 
    new Expectations() {{ 
     exampleclass.processFoo(); times = 1; 
    }}; 
    exampleclass.example(true); 
} 

Это должно высмеять метод processFoo, оставив все остальное неповрежденным и проверит, чтобы его вызывали ровно один раз.

0

Извините, что я немного опаздываю на вечеринку, но у меня есть пара идей для вас.

Во-первых, вы упомянули, что одним из вариантов является использование JMockit - это здорово, так как это дает вам большую гибкость. Если вы используете JMockit, то видимость вашего метода processFoo() не имеет большого значения. Давайте посмотрим, что это может выглядеть следующим образом:

public class Subject { 

    public void example (boolean foo) { 
     if (foo) { 
      processFoo(foo); 
     } 
     else if (foo==false) { 
      processSomethingElse(foo); 
     } 
    } 

    private void processFoo(boolean b) { 
     System.out.println("b = " + b); 
    } 

    private void processSomethingElse(boolean bb) { 
     System.out.println("bb = " + bb); 
    } 

} 

Так, один нюанс с этим вариантом, хотя в том, что я буду считать processFoo() представляет собой метод на ваш испытуемый, и я собираюсь использовать частичный макет, чтобы изменить тему теста - не то, что я действительно люблю делать, но это пример. В общем, лучше всего только издеваться над зависимостями вашего объекта теста, а не от поведения самого объекта теста - вам сообщили! Обратите внимание, что метод processFoo() объекта теста является закрытым. Я собираюсь подставить метод теста с частичным насмешкой JMockit, и видимость этого нового метода не должна соответствовать оригиналу.

import static org.assertj.core.api.Assertions.assertThat; 

import mockit.Mock; 
import mockit.MockUp; 
import mockit.integration.junit4.JMockit; 

import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 

@RunWith(JMockit.class) 
public class SubjectTest { 

    private Subject testSubject = new Subject(); 
    private boolean processFooCalled = false; 

    @Before 
    public void setup() { 
     new MockUp<Subject>() { 
      @Mock 
      public void processFoo(boolean b) { 
       processFooCalled = true; 
      }; 
     }; 
    } 

    @Test 
    public void should_call_processFoo() { 
     testSubject.example(true); 
     assertThat(processFooCalled).isTrue(); 
    } 

    @Test 
    public void should_not_call_processFoo() { 
     testSubject.example(false); 
     assertThat(processFooCalled).isFalse(); 
    } 

} 

Хорошо, так что это был первый вариант.Это на самом деле немного проще, если вы забыли JMockit для этого, если вы можете создать подкласс тестового объекта и переопределить метод processFoo():

public class Subject { 

    public void example (boolean foo) { 
     if (foo) { 
      processFoo(foo); 
     } 
     else if (foo==false) { 
      processSomethingElse(foo); 
     } 
    } 

    protected void processFoo(boolean b) { // NOTE: protected access here! 
     System.out.println("b = " + b); 
    } 

    private void processSomethingElse(boolean bb) { 
     System.out.println("bb = " + bb); 
    } 

} 

Таким образом, в этом случае стратегия просто подкласс вашего испытуемого объекта и заменить реализацию метода, который вы хотите наблюдать, вызываемого. Это может выглядеть так:

import static org.assertj.core.api.Assertions.assertThat; 

import org.junit.Test; 

public class SubjectTest2 { 

    private Subject testSubject = new TestableSubject(); 
    private boolean processFooCalled = false; 

    @Test 
    public void should_call_processFoo() { 
     testSubject.example(true); 
     assertThat(processFooCalled).isTrue(); 
    } 

    @Test 
    public void should_not_call_processFoo() { 
     testSubject.example(false); 
     assertThat(processFooCalled).isFalse(); 
    } 

    class TestableSubject extends Subject { 
     @Override 
     protected void processFoo(boolean b) { 
      processFooCalled = true; 
     } 
    } 
} 

Дайте ему вихрь. Надеюсь, поможет!

0

Не считайте, что вы делаете какие-либо частичные издевательства над этим, все, что вы делаете в этом случае, гарантирует, что если вы захотите реорганизовать свой код, ваши тесты потерпят неудачу. В модульном тестировании есть мантра - «никогда не проверяйте частные методы».

Что вы должны делать, это тестирование того, что метод, который вы вызываете, соответствует поведению, которое вы хотите видеть. В этом случае то, что происходит, когда верно foo, - это то, что важно, а не то, что он называет processFoo. Так что если foo истинно, вы хотите проверить, что действие processFoo выполняется верно и ничего больше.

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