Mockito - как проверить, что макет никогда не вызывался

Я ищу способ проверить с Mockito, что не было никакого взаимодействия с данным макетом во время теста. Легко добиться этого для данного метода с режимом проверки never(), но я еще не нашел решение для полного макета.

То, что я действительно хочу достичь: проверьте в тестах, что ничего не печатается на консоли. Общая идея с jUnit выглядит следующим образом:

private PrintStream systemOut;

@Before
public void setUp() {
    // spy on System.out
    systemOut = spy(System.out);
}

@After
public void tearDown() {
    verify(systemOut, never());  // <-- that doesn't work, just shows the intention
}

A PrintStream имеет множество методов, и я действительно не хочу проверять каждую отдельную проверку - и то же самое для System.err...

Поэтому я надеюсь, что если это будет простое решение, которое я могу, учитывая, что у меня есть хорошее покрытие для тестирования, заставьте инженеров-программистов (и меня) удалить их (мой) код отладки, например System.out.println("Breakpoint#1"); или e.printStacktrace(); до совершения изменений.

Ответ 1

Используйте это:

import static org.mockito.Mockito.verifyZeroInteractions;

// ...

private PrintStream backup = System.out;

@Before
public void setUp() {
    System.setOut(mock(PrintStream.class));
}

@After
public void tearDown() {
    verifyZeroInteractions(System.out);
    System.setOut(backup);
}

Ответ 2

verifyZeroInteractions(systemOut);

Как отмечено в комментариях, это не работает со шпионом.

Для грубо эквивалентного, но более полного ответа см. ответ gontard на этот вопрос.

Ответ 3

Вы можете попробовать немного другое:

private PrintStream stdout;

@Before public void before() {
    stdout = System.out;
    OutputStream out = new OutputStream() {
        @Override public void write(int arg0) throws IOException {
            throw new RuntimeException("Not allowed");
        }
    };
    System.setOut(new PrintStream(out));
}

@After public void after() {
    System.setOut(stdout);
}

Если вы предпочитаете, вы можете переключить анонимный тип для макета и проверить как предлагает Don Roby.

Ответ 4

Один из способов решения этой проблемы - реорганизовать тестируемый класс, чтобы можно было использовать PrintStream, который можно использовать для вывода. Это позволит вам unit test, не полагаясь на поведение класса System. Вы можете использовать конструктор private-package для этой инъекции, поскольку вы будете использовать его только из соответствующего тестового класса. Так что это может выглядеть примерно так.

public class MyClass{
    private PrintWriter systemOut;

    public MyClass(){
        this(System.out);
    }

    MyClass(PrintWriter systemOut){
        this.systemOut = systemOut;

        // ...any other initialisation processing that you need to do
    }
}

и внутри самого класса используйте переменную systemOut вместо System.out, где вы вызываете ее.

Теперь, в пределах тестового класса, создайте mock PrintStream и передайте его конструктору private-private, чтобы получить объект, который вы собираетесь тестировать. Теперь вы можете запускать любые действия, которые вам нравятся из ваших тестов, и использовать verify для проверки их эффектов на ваш макет PrintStream.