2017-02-23 6 views
0

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

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

public void startServer() throws IOException { 
    ServerSocket ss = new ServerSocket(portNum); 
    while(true) { 
    Socket s = ss.accept(); 
    Thread t = new Thread(new ConnectionHandler(s)); 
    t.start(); 
    } 
} 
+0

Цикл 'while (true)' трудно проверить, потому что тест никогда не закончится (если вы не сможете вызвать исключение, которое должно быть выбрано в течение while (true) -loop). ;-) –

+0

На всякий случай вы чувствуете склонность принять мой ответ; было бы здорово, если бы вы могли подумать об этом завтра ... поскольку я уже нажимал ежедневную кепку на день ;-) – GhostCat

ответ

4

Вкратце: код создает новый ServerSocket для прослушивания на определенном порту; и , когда «этот запрос» входит в этот порт, он запускает поток для обработки этого клиента.

Проблема с этим кодом:

  • Он проходит некоторое время (истина) цикл; так что метод не должен когда-либо возвращаться
  • И кроме того, это написано в трудно проверить путь; в основном потому, что у вас есть эти два вызова в new в этом методе.

Я объясню, как вы могли преодолеть вторую часть; а затем поговорим о первом пункте. Что касается самого «тестирования», у вас есть два варианта:

  1. Замок в PowerMock (уродливый); или, может быть, шпионы Мокито могли бы помочь; до mock Эти призывы к новому. (Mockito в порядке, но PowerMock не так много в моих глазах)
  2. Предпочтительно: изменить свой код, чтобы его было легко проверить; а затем использовать инъекцию зависимостей.

Как:

public class Server { 
    private final SocketFactory socketFactory; 
    private final ThreadFactory threadFactory; 

    public Server() { 
    this(new SocketFactory(), new ThreadFactory()); 
    } 

    Server(SocketFactory socketFactory, ... 
    this.socketFactory = socketFactory... 

public void startServer() throws IOException 
{ 
    ServerSocket ss = socketFactory.createSocketFor(portNum); 
    while(true) 
    { 
     Socket s = ss.accept(); 
     Thread t = threadFactory.newThreadFor(new ConnectionHandler(s)); 
     t.start(); 
    } 
} 

А теперь ... все супер просто: вы можете использовать этот второй пакет защищен CTOR для вставки издевался заводов; а затем вы можете настроить/убедиться, что эти заводы видят ожидаемые вами вызовы.

Конечно, это может выглядеть как «более» работа; так как теперь вам нужно создать эти два других класса (и на самом деле вы можете использовать интерфейсы плюс impl классы).Но дело в том, что вы получаете лучший дизайн, который не только легче тестировать, но и проще поддерживать и улучшать.

И затем: создание потоков «голого металла» на самом деле не является хорошей практикой. (особенно не в режиме while-true, если вы все еще ищете свою ошибку). Вы должны изучить какой-то класс ThreadPool; чтобы быть уверенным, что вы не постоянно создает новый темы. Это «дорогие»; вы должны очень предпочесть «повторное использование» потоков. И есть библиотеки, которые помогают с этим!

OK, возвращаясь к другой проблеме: как сейчас, вы просто не может разумно блока теста этого метод из-за некоторое время (правда). Вы видите, когда вы mock, что ServerSocket, то вызов accept() не будет блокироваться; и вы столкнулись с каким-то бесконечным циклом, создавая насмешливые потоки.

Итак: вам нужно либо переработать этот код (чтобы его можно было остановить извне) ... или вы могли бы настроить макет ThreadFactory, чтобы вернуть mocked thread; что вызывает какое-то конкретное исключение. И тогда ваш модульный тест просто ожидает, что исключение будет выбрано - как косвенное «доказательство», что все, что вы ожидали, действительно имело место.

+0

только один вопрос, о фактическом цикле while, почему это не создает потоки навсегда, пока система не закончится ресурсов? Я заметил, что код в ConnectionHandler реализован как одноэлементный, это имеет значение? –

+0

Нет. Это потому, что accept() будет блокировать до тех пор, пока соединение не вступит. Таким образом, половина моего ответа неверна. Неловко. Я исправлю это позже сегодня, когда я возьмусь за настоящую клавиатуру. – GhostCat

+0

OK; обновил мой ответ. Если вам нравится моя работа; не стесняйтесь повышать свой ответ или мой вопрос ;-) – GhostCat

1

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

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

Я планирую написать модульные тесты, чтобы полностью покрыть обработчик соединения, а затем создать тестовую проводку (отдельную программу, которую вы можете запустить в другом jvm), чтобы создавать потоки для подключения к этому.

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