2016-10-03 3 views
1

У меня возникла проблема с запуском тестов JUnit на моем сервере. Когда я запускаю тест на своей машине, нет никаких проблем. Когда я запускаю его на сервере, на моем сервере иногда происходит сбой. Это означает, что тесты проходят иногда в 60% попыток и 40% неудачных попыток.JUnit одновременный доступ к synchronizedSet

Я использую Mockito. Мой тест начинается с издевательства над некоторыми ответами, используя MessageListener и сопоставляя каждый запрос с ответом и под капотом. Я использую Collections.synchronizedSet(new HashSet<>()), который является потокобезопасным. (Каждая модификация моего синхронизированного набора происходит в synchronized(mySynchronizedSet){....}). Затем я использую RestAssurd, чтобы получить ответ конкретной конечной точки REST и утверждение некоторых значений.

Когда тест не удается и я смотрю на Stacktrace, я вижу, что одно из моих сопоставлений (всегда на одном объекте) не работает, и нет никакой карты между этим конкретным запросом и ответом в моей коллекции и, естественно, Я получаю null по запросу этой конечной точки.

Я использую Jenkins для автоматизации компиляции и запуска теста, и я нахожу трассировку стека неудачей или мой Printlns в противном случае, нет доступных средств отладки.

Это звучит как проблема параллелизма для меня. Я имею в виду, что моя коллекция не успевает подготовиться до запроса RestAssurd для конечной точки. Я проверил блокировки, сон и еще одно простое решение для параллельной работы Java, но они не помогают, и вероятностный характер этой проблемы привел меня в тупик.

Каждая мысль будет оценена.

ответ

2

Судя по тому, что вы сказали, кажется, у вас есть непонимание того, как все работает в 3 конкретных случаях.

Первый

и самый очевидный, и я извиняюсь за это, даже не упоминая, но причина, по которой я делаю все это, потому что я собираю, что вы все еще учимся (я прошу прощения дальше если вы» я все еще не изучаю! и с той же скоростью вы, возможно, даже не подразумевали это так, как я его читал, поэтому извините, если я неправильно прочитал): вы не компилируете с Дженкинсом, вы компилируете с любым вкусом JDK, который у вас есть на вашей машине (будь то Oracle, Apple, GCJ и т. д.). Дженкинс - инструмент автоматизации, который помогает вам выполнять утомительные задания, которые вы планируете регулярно запускать. Я только упоминаю об этом, потому что я знаю, что студенты в настоящее время используют IDE в там, где открываются классы, и не могут различать компилятор, среду выполнения и IDE.

Во-вторых

с помощью поточно-библиотеки, он автоматически не делает все, что вы делаете по своей сути THREADSAFE. Рассмотрим следующий пример:

final Map<Object, Object> foo = Collections.synchronizedMap(new HashMap <>()); 
    final String bar = "bar"; 
    foo.put(bar, new Object()); 
    new Thread(new Runnable(){ 
     @Override 
     public void run(){ 
      foo.remove(bar); 
     } 
    }).start(); 
    new Thread(new Runnable(){ 
     @Override 
     public void run(){ 
      if(foo.containsKey(bar)){ 
       foo.get(bar).toString(); 
      } 
     } 
    }).start(); 

Там нет никакой гарантии, что вызов второго потока к #get(Object) будет происходить до или после вызова первого потока к #remove(Object).Учтите, что

  1. второй поток можно назвать #containsKey(Object)
  2. затем первый поток получает процессорное время и вызывает #remove(Object)
  3. тогда второй поток теперь имеет процессорное время и вызывает #get(Object)

в этой точке , возвращаемое значение от get(Object) будет равно NULL, а вызов #toString() приведет к ошибке NullPointerDereference. Вы говорите, что используете Set, поэтому этот пример с использованием карты в основном заключается в том, чтобы доказать точку: только потому, что вы используете коллекцию потокобезопасности, автоматически не делает все, что вы делаете threadafe. Я полагаю, что есть вещи, которые вы делаете с вашим набором, которые соответствуют этому типу поведения, но без фрагментов кода, я могу только догадываться.

И наконец

Вы должны быть осторожны с тем, как вы пишете JUnits. Правильный тест JUnit - это то, что называется «белым ящиком». Другими словами, вы знаете все, что происходит в тесте, и вы явно проверяете все, что происходит только в тестируемой единице. Тестируемое устройство - это всего лишь метод, который вы вызываете - не методы, вызываемые вашим методом, только сам метод. Что это значит, так это то, что вам нужна хорошая фальшивая каркас и издеваются над любыми последующими вызовами метода, которые может вызвать ваш тестируемый блок. Некоторые хорошие рамки - JMockit, Mockito + PowerMock и т. Д.

Важность этого заключается в том, что ваш тест должен проверять ваш изолированный код. Если вы разрешаете доступ к сети, доступ к диску и т. Д., Тогда ваш тест может потерпеть неудачу, и он может не иметь ничего общего с написанным вами кодом и полностью лишает его цели. В вашем случае вы намекаете на доступ к сети, поэтому представьте, что проблема с пропускной способностью связана с вашими коммутаторами/маршрутизаторами/и т. Д. Или что ваш буфер NIC заполнен и не может обрабатываться достаточно быстро для того, что пытается ваша программа. Несомненно, неудача не очень хорошая и должна быть исправлена, но это должно быть протестировано при тестировании «черного ящика». Ваши тесты должны быть написаны так, чтобы вы исключили такие проблемы из присутствия и только проверили свой код в конкретном методе тестируемого устройства и ничего больше.

Edit: Я на самом деле отправил ответ на отдельное обсуждение о тестировании Whitebox, которые могут иметь отношение: Is using a test entity manager a legitamate testing practice?

+0

Хороший ответ, но две вещи: А) Я Wouldnt даже упомянуть Powermock сторону новичка, и B) иметь в виду, что да, JUnit в основном предназначен для «модульных тестов»; но этот термин очень широк, и многие люди используют Junit для любых тестов, и это нормально. JUnit - это просто инструмент, и он работает для истинных модульных тестов, но также и для любого другого теста. – GhostCat

+0

Справедливые точки. Что касается PowerMock, я не уверен, что это так. Тестирование Whitebox, которое вы должны знать обо всех этих вещах, даже начать делать это правильно, и я скажу, что Mockito + PowerMock гораздо более ручны, чем JMockit, поэтому я бы предпочел упомянуть об этом. Mockito + PowerMock читается как английский, в то время как JMockit действительно трудно читать и понимать, как это работает, на мой взгляд, в любом случае. Я обнаружил, что разработчики, которые не погружаются в детали должным образом насмешки, заканчивают неправильными модульными тестами, и тесты заканчиваются тем, что они не делают то, что, как они думают, делают. У него может не быть выбора – searchengine27

+0

Вещь: кому-то нужен Powermock, когда дизайн использует ** статический ** в неправильном месте; или ** новый ** без надлежащего мышления. Другими словами: при написании нового кода потребность в Powermock напрямую переводится на «плохой дизайн» в моих глазах. После просмотра этих видеороликов https://www.youtube.com/playlist?list=PLD0011D00849E1B79 ... Я понял, что мне абсолютно не нужен Powermock (и различные мелкие и большие проблемы, которые часто приходят с ним); и уже много месяцев я не пожалел, что полностью прекратил его использовать. – GhostCat

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