2016-10-15 10 views
2

Во-первых, весь код находится в https://github.com/JJ/spray-test Я использую глобальный объект (который я не знаю, является ли это правильным поведением Scala) для совместного использования состояния в приложении Spray. put добавляет к карте, get получает значения из карты, таким образом:Weird Scala поведение теста с глобальными переменными: в том числе задержка делает его успешным

path(Segment) { quien => 
    get { 
     println(Apuestas) // also Thread.wait(100) 
     val esta_apuesta = Apuestas.get(quien) 
     complete(esta_apuesta) 
    } 
    } 

(пожалуйста, проверьте весь файл https://github.com/JJ/spray-test/blob/master/src/main/scala/info/CC_MII/MyService.scala)

Основные части тестового кода

"Crea apuestas correctamente" in { 
     Put("/0/2/Alguien") ~> myRoute ~> check { 
    response.entity should not be equalTo(None) 
    responseAs[String] must contain("Alguien") 
     } 

     Put("/3/0/Menda") ~> myRoute ~> check { 
    response.entity should not be equalTo(None) 
    responseAs[String] must contain("Menda") 
     } 
    } 

    "GET recupera apuesta correctamente" in { 
     Get("/Alguien") ~> myRoute ~> check { 
    response.entity should not be equalTo(None) 
    responseAs[String] must contain("Alguien") 
     } 
    } 

Проблема заключается в первом фрагменте кода. Если я прокомментирую заявление println, он не работает, и он терпит неудачу. Это сообщение об ошибке: [error] 'There was an internal server error.' doesn't contain 'Alguien' (MyServiceSpec.scala:49) Что очевидно указывает на то, что часть «получить» еще не работает, или она находится в другом потоке, или я действительно не знаю, что случилось.

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

Я также включил это как проблему в репо с лейблом hacktoberbest, на случай, если кто-то заинтересован в продвижении одного PR в этой области. https://github.com/JJ/spray-test/issues

Update: Это, кажется, связано с этим вопросом: Unintended change to local variable of a Scala Actor, то есть субъекты не должны разделять государства, но это до программы для обеспечения соблюдения его. Дело в том, что они делают делить состояние, но только если мы печатаем. Возможно, введение задержки в поток имеет такой же эффект? Я знаю, что это плохая форма, худшая практика и все остальное, но, как сказано выше, я бы с радостью просветил правильный способ сделать это.

второе обновление: Я пытался синхронизировать методы таким образом:

def add(apuesta: Apuesta): Apuesta = synchronized { 
    { 
     this.apuestas += (apuesta.quien -> apuesta) 
    } 
    apuesta 
    } 

Еще нет костей. Я все равно должен либо распечатать весь объект Apuesta, либо ждать в потоке, что вызывает больше проблем. Что делает println сделать это через синхронизацию?

Обновление 3: После тестирования какое-то время println только «синхронизирует» часть времени. Все еще происходит случайным образом. Это как-то связано с таймингом, но не может понять, как это сделать.

+0

Это не странное поведение, это просто способ, которым параллелизм выглядит для нас человеком. Существуют некоторые инструменты и модели, которые предназначены для устранения трудностей с отслеживанием потока параллельного приложения, но они работают только в том случае, если вы подчиняетесь их ограничениям. Такие ограничения, как отсутствие общего состояния и т. Д. Хороший момент для запуска: https://www.packtpub.com/application-development/learning-concurrent-programming-scala – michaJlS

+0

Итак, чтобы не переписывать все, что-то, что можно сделать по этому поводу ? – jjmerelo

ответ

2

Это не так, потому что у вас есть зависимость между тестами. Put("/0/2/Alguien") должен быть заполнен до того, как вы отправите запрос Get("/Alguien"). В противном случае у вас нет записи с ключом alguien в info.CC_MII.Apuestas#apuestas, и когда вы пытаетесь получить к нему доступ, ваши приложения терпят неудачу.

Вы вводили задержку в форме print или непосредственно с помощью Thread.wait(100), и таким образом дали время Put запрос на заполнение. Было бы немного лучше, если бы вы как-то задерживали выполнение теста для GET вместо того, чтобы печатать или спать в сервисе.

Другой вариант (лучше) мог бы сделать состояние впрыска в info.CC_MII.Apuestas, начальное значение для карты apuestas. Затем вы можете предоставить несколько записей во время тестирования и попытаться получить их с помощью запроса Get вместо Alguien.

+0

Это не совсем проблема. Во-первых, на тестовой стороне вызовы завершаются или предыдущие тесты потерпели бы неудачу. Невозможно даже выполнить последовательность вызовов, кроме программных. Во-вторых, на стороне сервера Thread.wait вызывает некоторые проблемы: он просто отключает вызовы, если тест выполняется сразу после. Плюс забавная вещь о println, о которой я упомянул, заключается в том, что она должна включать переменную или она не будет работать. печать пинает какую-то переменную магию. Я не знаком с ... Thread.wait тоже не работает. – jjmerelo