Извините, что я немного опаздываю на вечеринку, но у меня есть пара идей для вас.
Во-первых, вы упомянули, что одним из вариантов является использование 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;
}
}
}
Дайте ему вихрь. Надеюсь, поможет!
Возможный дубликат [Unit testing and assert case for void method] (http://stackoverflow.com/questions/8230150/unit-testing-and-assert-case-for-void-method) –
Вы можете создать ' spy' класса под тестом, бросая какое-то исключение, когда вызывается метод processFoo. Если вы поймаете это исключение, все будет в порядке, иначе этот метод не был вызван. – bsiamionau
Боковое примечание: 'foo' может быть истинным или ложным. Поэтому ваш код должен быть 'if (foo) {..} else {...}'. –