Странное поведение теста Scala с глобальными переменными: включение задержки делает его успешным

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

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

Обновление: похоже, это связано с этим вопросом: Непреднамеренное изменение локальной переменной актера Scala, то есть акторы не должны совместно использовать состояние, но программа должна обеспечить его соблюдение. Дело в том, что они действительно разделяют состояние, но только если мы печатаем. Может быть, введение задержки в потоке будет иметь тот же эффект? Я знаю, что все это плохая манера, наихудшая практика и все такое прочее, но, как сказано выше, я был бы счастлив узнать, как это сделать.

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

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

До сих пор нет кости. Мне все еще нужно либо распечатать весь объект Apuesta, либо подождать в потоке, что вызывает больше проблем. Что делает println, чего нельзя сделать с помощью синхронизации?

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


person jjmerelo    schedule 15.10.2016    source источник
comment
Это не совсем странное поведение, это просто то, как параллелизм выглядит для нас, людей. Есть некоторые инструменты и модели, которые предназначены для смягчения трудностей с отслеживанием потока параллельного приложения, но они работают только в том случае, если вы соблюдаете их ограничения. Ограничения, такие как отсутствие общего состояния и т. д. Хорошая точка для начала: packtpub.com/ разработка приложений/   -  person michaJlS    schedule 16.10.2016
comment
Итак, если не переписывать все заново, можно ли что-нибудь с этим сделать?   -  person jjmerelo    schedule 16.10.2016


Ответы (1)


Это не удается, потому что у вас есть зависимость между тестами. 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.

person michaJlS    schedule 16.10.2016
comment
Это не совсем похоже на проблему. Во-первых, на тестовой стороне вызовы завершены, иначе предыдущие тесты завершились бы неудачей. Нет даже способа упорядочить вызовы, кроме как программно. Во-вторых, на стороне сервера Thread.wait создает некоторые проблемы: он просто сбрасывает вызовы, если тест выполняется сразу после него. Кроме того, забавная вещь в println, которую я упомянул, заключается в том, что она должна включать переменную, иначе она не будет работать. печать запускает некоторую магию переменных, с которой я не знаком ... Thread.wait также не работает в тесте. - person jjmerelo; 16.10.2016