Как мне выполнить модульный тестовый код, который использует библиотеки Google Guava, особенно вещи из пакета IO? - PullRequest
7 голосов
/ 16 июля 2011

Большая часть функциональности в гуаве обеспечивается статическими методами.Я не понял, как объединить использование библиотек гуавы и хорошую практику внедрения зависимостей.

Например, если бы мне пришлось использовать

Files.readLines(File, Charset)

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

Полагаю, возможно, что я мог бы написать адаптер для всех, кто мне интересен?Но это может закончиться большой работой ...

Я нахожу странным, что библиотеки гуавы приходят от одного и того же набора людей, которые обеспечивают хитрость и пишут сообщения в блогах, такие как this

Ответы [ 6 ]

4 голосов
/ 17 июля 2011

тьфу, страшные статические методы.Я слышал, что JMockit способен снимать статику, но сам никогда не пробовал.Решением, которое я обычно использую, является Адаптер.

public class FilesAdapter {

    private final File file;

    public FilesAdapter( File file ) {
        this.file = file;
    }

    public List<String> readLines( Charset charset ) {
        return Files.readLines( file, charset );
    }
}

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

GUICE способен впрыскивать конкретные объекты, а также макетные структуры, такие как JMock2 и Mockito, также могут имитировать бетоны.Это все дело ученых, и разные люди будут иметь разные мнения.

Если бы вы использовали GUICE, вы бы завернули этого парня на фабрику для инъекционного совершенства.

public class FilesAdapter {

    private final File file;

    @Inject
    protected FilesAdapter( @Assisted File file ) {
        this.file = file;
    }

    public List<String> readLines( Charset charset ) {
        return Files.readLines( file, charset );
    }

    public interface Factory {
        FilesAdapter create( File file );
    }
}
3 голосов
/ 16 июля 2011

Мы предоставили библиотеку common.io в качестве временного промежутка, пока вы, наконец, не получите настоящий, правильный API файловых систем в JDK 7. Эта библиотека будет основана на интерфейсе и очень удобна для тестирования.

2 голосов
/ 26 июля 2011

Powermock позволяет макетировать статические методы .

Мы используем его здесь и там, и я могу засвидетельствовать, что это работает.

0 голосов
/ 30 августа 2013

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

В общем, это не проблема для решения с помощью DI и макетов. Некоторые зависимости просто не стоит явно вводить, если они достаточно распространены, чтобы считаться зависимостями, и вы достаточно уверены, что они работают так, как рекламируется. Я думаю, что Гуава попадает в эту категорию. Аналогичным образом, mocks отлично справляются с манипуляциями с состоянием, а статические методы не должны так уж и мешать, так что вы не получите большого выигрыша, даже если вам удастся их макетировать.

0 голосов
/ 18 июля 2011

Прежде всего, почему бы просто не позволить вашим модульным тестам затронуть файловую систему?Обычно чтение небольших локальных специфичных для теста файлов в нескольких тестах не добавляет ощутимых задержек к запуску теста.

Но если вы действительно не хотите прикасаться к файловой системе, просто поиздевайтесь с ней.Например, должен работать следующий тест на основе JMockit :

@Test
public void someTest()
{
    new Expectations() {
        @Mocked Files files;
        @Input  List<String> lines = asList("Line 1", "Another line", "...");
    };

    // Called from code under test:
    List<String> lines = Files.readLines(someFile, charSet);
    // These "lines" will be the same as the "@Input" lines.

    // asserts...
}
0 голосов
/ 16 июля 2011

Вы можете изолировать статическую зависимость в своем собственном методе (который затем может быть переопределен для целей тестирования, как показано ниже).Обычно изолированный метод имел бы «защищенную» видимость.

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import java.io.File;

import org.junit.Before;
import org.junit.Test;

public class FileUtilsTest {

    private static final String[] TEST_LINES = { "test 1", "test 2", "test 3" };
    private static final File TEST_FILE = new File("/foo/bar");
    private FileUtils fileUtils;

    /**
     * Configure reusable test components
     */
    @Before
    public void setUp() {
        fileUtils = spy(new FileUtils());
        when(fileUtils.getLines(any(File.class))).thenReturn(TEST_LINES);
    }

    /**
     * Ensure the {@link FileUtils#countLines(File)} method returns the correct line count (without hitting the
     * file-system)
     */
    @Test
    public void testCountLines() {
        assertEquals(3, fileUtils.countLines(TEST_FILE));
    }

    /**
     * The class we want to test
     */
    public static class FileUtils {

        /**
         * Method that we want to test
         */
        public int countLines(final File file) {
            return getLines(file).length;
        }

        /**
         * Static dependency isolated to a method (that we can override, for test purposes)
         */
        public String[] getLines(final File file) {
            return Files.readLines(file);
        }
    }

    /**
     * Poorly written utility class with hard-to-test static methods
     */
    public static class Files {

        public static String[] readLines(final File file) {
            // In reality, this would hit the file-system
            return new String[] { "line 1" };
        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...