Тестирование outputstream.write (‹String›) без создания файла

Я тестирую выходной поток в java примерно так, как показано ниже.

    Writer outputStream = getOutputStream(fileName);
    if(outputStream != null) {
        try {
            outputStream.write(inputText);
        }
        finally {
            outputStream.close();
        }
    }
    else {
        throw new IOException("Output stream is null");
    }

Я пишу тест mockito, как показано ниже

public void testFileWrite() throws IOException {
    when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);
    doNothing().when(outputStreamMock).write(Matchers.anyString());
    doNothing().when(bufferedReaderMock).close();

    testObj.write(outputFileNameValidValue, reveredFileInput);

    verify(outputStreamMock).write(Matchers.anyString());
    verify(outputStreamMock).close();
}

Проблема в том, что при создании OutputStreamWriter(new FileOutputStream(filename)) создается физический файл на диске.

Можем ли мы протестировать Outputstream.write, фактически не записывая файл на диск?

Спасибо ананд


person Anand    schedule 17.02.2012    source источник
comment
Уточните, где вы создаете OutputStreamWriter - я не вижу этого в вашем коде. Я предполагаю, что это внутри getOutputStream - за исключением того, что вы отключили этот метод. Вам нужно опубликовать весь свой код, если вы хотите, чтобы люди хорошо помогали вам. Кроме того, getOutputStream, вероятно, следует назвать как-то иначе (возможно, makeWriter), потому что он не получает OutputStream.   -  person Dawood ibn Kareem    schedule 18.02.2012
comment
В методе getOutputStream. Причина, по которой я переместил его в метод, в надежде, что mockito не запустит метод и не вернет макет. но я ошибаюсь.   -  person Anand    schedule 18.02.2012
comment
После поиска в Google и чтения нескольких документов выяснилось, что PowerMock может с этим легко справиться. С expectNew или с помощью suppressConstructor и Whitebox.setInsternalState. С PowerMock очень легко протестировать такие вещи. Спасибо всем за комментарии и ответы .. С уважением, Ананд Бархате   -  person Anand    schedule 18.02.2012


Ответы (5)


Вы можете использовать ByteArrayOutputStream, который записывает данные в память. Вы можете прочитать это с помощью ByteArrayInputStream.

Альтернативой является запись ожидающего OutputStream, который не работает, как только вы пытаетесь записать неправильный байт. Это может быть полезно, чтобы увидеть, где именно и почему тест не проходит.

person Peter Lawrey    schedule 17.02.2012
comment
Хорошо .. так что используйте ByteArrayOutputStream для записи, а потом мне придется использовать writeTo для записи в файл? Но рано или поздно я столкнусь с той же проблемой, не так ли? XXStreamWriter должен будет записать файл, и это тот бит, которого я хочу избежать при использовании Mockito. - person Anand; 17.02.2012
comment
Я не понимаю. Зачем вам нужно писать в файл? - person Peter Lawrey; 17.02.2012

Вы можете попробовать использовать System.out для вывода, который на самом деле является Printstream, который является подклассом OutputStream.

см. http://docs.oracle.com/javase/6/docs/api/java/lang/System.html http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html

person nwaltham    schedule 17.02.2012

Как уже было предложено другими, вам нужно иметь возможность вводить mocked OutputStream в свой тестируемый класс. Поскольку вашему тестируемому классу требуется OutputStream, который записывает в заданный файл, вам нужно будет внедрить фиктивный OutputStreamFactory в тестируемый класс.

У меня есть для вас полностью самодостаточный код:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;
import java.io.OutputStream;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class Test9328173 {

    private ClassUnderTest testObj;

    @Mock
    private OutputStreamFactory factory;

    @Mock
    private OutputStream stream;

    @Before
    public void setUp() throws Exception {
        testObj = new ClassUnderTest();
        testObj.factory = factory;
    }

    @Test
    public void testFileWrite() throws Exception {
        when(factory.create("filename")).thenReturn(stream);

        testObj.write("filename", new byte[]{1, 2, 3});

        verify(stream).write(new byte[]{1, 2, 3});
        verify(stream).close();
    }

    private class ClassUnderTest {

        private OutputStreamFactory factory;

        public void write(String filename, byte[] content) throws IOException {
            OutputStream stream = factory.create(filename);
            try {
                stream.write(content);
            } finally {
                stream.close();
            }
        }
    }

    private interface OutputStreamFactory {

        OutputStream create(String filename);
    }
}
person Alexander Kiel    schedule 06.03.2012
comment
Верно. Аргумент установщика / конструктора / аннотация @Inject может быть немного проще, чем фабрика, но это способ проверить, что поток получает правильные инструкции. - person avandeursen; 07.03.2012

Вы должны смоделировать свой getOutputStream: is, который должен возвращать фиктивный объект потока вывода. Вызов new FileOutputStream действительно создает файл на диске.

Теоретически вы можете создать макет самой файловой системы, но это намного сложнее.

И BTW if(outputStream != null) является избыточным: поток никогда не может быть нулевым. Если его невозможно создать, метод должен выдать исключение. Это не C, это Java. :)

person AlexR    schedule 17.02.2012
comment
Собственно, это то, что я сделал, когда (testObj.getOutputStream (outputFileNameValidValue)). ThenReturn (outputStreamMock); но когда я вызываю testObj.write (outputFileNameValidValue, reveredFileInput); он все равно будет записывать в файл пустую строку. Так что, похоже, мне придется издеваться над файловой системой, чтобы избежать фактического создания файла на диске. - person Anand; 17.02.2012
comment
if (outputStream! = null) согласны с этим. Я просто привык к защитному программированию :) - person Anand; 17.02.2012

Вы должны заставить высмеянный getOutputStream(String) вернуть java.io.StringWriter, и тогда вы сможете утверждать, что ожидаемый контент был написан.

public void testFileWrite() throws IOException {
    StringWriter writer = new StringWriter();
    when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(writer);

    testObj.write(outputFileNameValidValue, reveredFileInput);

    assertEquals(reveredFileInput, writer.toString());

    verify(writer).close();
}
person Justin Muller    schedule 18.02.2012