2016-10-15 1 views
2

Tout d'abord, le code entier est en https://github.com/JJ/spray-test J'utilise un objet global (que je ne sais pas si c'est un comportement propre à Scala) pour partager l'état dans une application de pulvérisation. put ajoute à une carte, get obtient des valeurs à partir d'une carte, ainsi:Weird Scala comportement de test avec des variables globales: y compris un retard le fait réussir

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

(s'il vous plaît vérifier le fichier entier à https://github.com/JJ/spray-test/blob/master/src/main/scala/info/CC_MII/MyService.scala)

Les parties essentielles du code de test est

"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") 
     } 
    } 

Le problème est dans le premier morceau de code. Si je commente l'instruction println, cela ne fonctionne pas et échoue. Ceci est le message d'erreur: [error] 'There was an internal server error.' doesn't contain 'Alguien' (MyServiceSpec.scala:49) Ce qui indique clairement que la partie "get" n'a pas encore fonctionné, ou est dans un autre thread, ou je n'ai vraiment aucune idée de ce qui se passe. Cela a probablement quelque chose à voir avec la synchronisation et quelque chose et je devrais probablement avoir et déclarer Apuestas d'une autre manière, mais je suis assez nouveau à ce sujet et je serais très heureux d'être éclairé.

J'ai également inclus cela comme un problème dans le rapport avec l'étiquette hacktoberbest, juste au cas où quelqu'un est intéressé à faire avancer un PR dans ce domaine. https://github.com/JJ/spray-test/issues

Mise à jour: Cela semble être lié à cette question: Unintended change to local variable of a Scala Actor, qui est, les acteurs ne doivent pas partager l'état mais il est au programme pour l'appliquer. La chose est, eh bien, ils faire l'état de partage, mais seulement si nous imprimons. Peut-être que l'introduction d'un retard dans le fil aura le même effet? Je sais que c'est de la mauvaise forme et de la pire pratique et tout le reste, mais comme je l'ai dit plus haut, je serais heureusement éclairé par la bonne façon de le faire.

2ème mise à jour: J'ai essayé de synchroniser des méthodes ainsi:

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

Toujours pas de dés. Je dois encore imprimer l'ensemble de l'objet Apuesta ou bien attendre dans le fil, ce qui pose plus de problèmes. Que fait println qui ne peut pas être fait via la synchronisation?

Mise à jour 3: Après un test pendant un certain temps, println ne fait que "synchroniser" une partie du temps. Échoue toujours au hasard. Cela a quelque chose à voir avec le timing, mais je ne vois pas comment.

+0

Ce n'est pas vraiment un comportement étrange, c'est juste la façon dont la concurrence nous semble humaine. Certains outils et modèles sont destinés à atténuer les difficultés de suivi des flux d'applications concurrentes, mais ils ne fonctionnent que si vous respectez leurs contraintes. Contraintes comme pas d'état partagé etc. Bon point pour commencer: https://www.packtpub.com/application-development/learning-concurrent-programming-scala – michaJlS

+0

Donc, à moins de tout réécrire, est tout ce qui peut être fait à ce sujet ? – jjmerelo

Répondre

2

Il échoue parce que vous avez une dépendance entre les tests. Put("/0/2/Alguien") doit être terminé avant d'émettre une demande Get("/Alguien"). Sinon, vous n'avez aucune entrée avec la clé alguien dans le info.CC_MII.Apuestas#apuestas et lorsque vous tentez d'y accéder, vos applications échouent.

Vous avez introduit le délai, sous la forme print ou directement en utilisant Thread.wait(100), et de cette manière a donné le temps à Put de compléter la requête. Ce serait juste un peu mieux, si vous retardez l'exécution du test pour GET au lieu de mettre l'impression ou le sommeil dans le service.

L'autre option (mieux) pourrait permettre d'injecter l'état dans info.CC_MII.Apuestas, la valeur initiale pour la carte apuestas. Ensuite, vous pouvez fournir quelques entrées lors des tests mis en place, et essayez de les récupérer avec la demande Get au lieu de Alguien.

+0

Cela ne semble pas être le problème. D'abord, du côté des tests, les appels sont terminés ou les tests précédents auraient échoué. Il n'y a même pas moyen de séquencer les appels autrement que par programme. Deuxièmement, du côté du serveur, Thread.wait provoque des problèmes: il supprime simplement les appels si le test est effectué immédiatement après. De plus, la chose amusante à propos de l'impression que j'ai mentionnée est qu'il est nécessaire d'inclure la variable ou cela ne fonctionnera pas. l'impression donne un coup de magie variable que je ne connais pas ... Thread.wait ne fonctionne pas non plus en test. – jjmerelo