2010-11-15 3 views
1

Это класс, который я должен испытания:Как создать частный/окончательный метод, доступный для насмешек?

public class Downloader { 
    public String download(String uri) { 
    HttpClient client = this.getHttpClient(); 
    client.setURI(uri); 
    return client.get(); 
    } 
    private HttpClient getHttpClient() { 
    HttpClient client = new HttpClient(); 
    // + some config 
    return client; 
    } 
} 

Очень просто. Теперь я хочу проверить его поведение, когда getHttpClient() выдает исключение. Однако я не могу издеваться над этим методом, так как это private. Что такое обычная практика в такой ситуации?

ответ

3

Я бы сделал HTTPClient полем класса, установленным при построении (через интерфейс). Тогда у вас есть возможность создать макет HTTPClient, который может вызвать исключение во время теста, если вы хотите, например .:

public class Downloader { 
    private IHTTPClient client; 

    public Downloader(IHTTPClient client) { 
    this.client = client; 
    } 

    public String download(String uri) { 
    this.initialiseHttpClient(); 
    client.setURI(uri); 
    return client.get(); 
    } 

    private HttpClient initialiseHttpClient() { 
    // + some config 
    } 
} 

Затем вызовите конструктор с реальным HTTPClient в производстве код и Mock в тестовом коде. Возможно, вам понадобится создать оболочку для HTTPClient для реального кода.

+2

+1, но если вы собираетесь инициализировать введенный объект http-клиента, может возникнуть больше смысла вводить фабрику http-клиентов вместо этого с помощью метода 'create', который принимает необходимые параметры. –

+0

Отлично, именно то, что я искал! – yegor256

0

Это звучит немного дрянной, но я обычно делаю такие методы, как эта публика, и добавляю заметные javadocs, говорящие: «Этот метод открыт для публики только для тестирования».

Вы также можете использовать доступ к пакету только с помощью xunit/mock и т. Д. В том же пакете.

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

1

Если вы пытаетесь проверить частные методы, я думаю, что что-то не так.

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

may необходимо заменить некоторые функции в вашем классе для целей тестирования (например, заменить в сломанном соединении JDBC и т. Д.). В этом сценарии я буду исследовать насмешливую и зависимую инъекцию.

+0

Я думаю, что это не совсем правильно. Единичные тесты не являются испытаниями черного ящика; они не просто проверяют публичный контракт. Они могут тестировать любое ожидаемое взаимодействие между объектом и его средой. Например, вы можете проверить, что метод 'download' вызывает вызов для инъецируемого интерфейса HttpClientProvider. Это деталь реализации, которая не представляет интереса для клиентского кода, но это * * то, что вы, возможно, захотите проверить. –

+0

Одной из целей модульных тестов является охват кода тестируемого кода. – seand

+0

@Seand - Существует разница между утверждением хорошего покрытия кода и явным тестированием частных методов. Во всех случаях используйте все сценарии, используя ваши тесты, но прыгать через обручи для проверки частных методов - это не способ сделать это. –

0

Вы могли бы сделать getHttpClient (защищены) и подкласс в тесте, чтобы вернуть то, что вы хотите, так что вы должны были бы что-то подобное в ваших тестах:

public class TestableDownloader extends Downloader { 

    protected HttpClient getHttpClient() { 
    throw new Exception(); 
    } 
} 

Это не идеально, хотя, вы Лучше иметь другой дизайн, который не требует от вас тестирования частных методов (возможно, с помощью инъекции зависимостей, чтобы обеспечить фабрику или что-то еще).

0

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

Стыковка также бесполезная вещь. Если вам нужно что-то издеваться, ваш метод действительно интегрирует функции. Ваш код нуждается в рефакторинге, чтобы сделать его только одним делом, а затем метод обёртки вызывает его, и он будет издеваться над объектом для его интеграции.

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

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