2016-06-09 11 views
2

So habe ich einige Server-Code mit einem Endpunkt, wo ich Sachen asynchron ausführen möchte. Zu diesem Zweck verwende ich Futures. Es gibt Aufgaben, die zu dem Ergebnis führen, aber es gibt auch teuer IO Aufgaben, die dies nicht tun, so führe ich sie in einem Feuer und vergessen Zukunft etwa so:Scala Testen mit Feuer und vergessen Futures

import scala.concurrent.Future 

val ec = scala.concurrent.ExecutionContext.global 

Future { 
    Thread.sleep(10000) 
    println("Done") 
}(ec) 

println("Exiting now") 

Ausgabe das heißt:

import scala.concurrent.Future 

ec: scala.concurrent.ExecutionContextExecutor = [email protected] 

res0: scala.concurrent.Future[Unit] = [email protected] 

Exiting now 
res1: Unit =() 

Normalerweise auf dem Server ist dies nicht so ein großes Problem, weil der Kontext weiterläuft, da er andere Aufgaben erhält und damit die IO fertigstellen kann. Aber wenn ich teste, endet der Test und die Aufgaben drinnen beginnen zu werfen, weil die Dienste, die sie benutzen, nicht verfügbar sind.

Die Frage ist also: Wie warte ich auf diese Feuer und vergiss Futures ohne auch meine Hauptausführung zu blockieren?

+0

Sie müssen auf jeden Fall die Hauptausführung blockieren. – Nyavro

+0

Können Sie auch den Testcode einfügen. – curious

+0

@Nyavro Das möchte ich wirklich nicht. Fehler werden auf dem Server protokolliert und müssen nicht an den Client weitergegeben werden. Wir sprechen davon, 3-5 Sekunden zur Reaktionszeit hinzuzufügen, wenn ich auf das IO warte. – mirosval

Antwort

2

Um meine Antwort zu veranschaulichen, stellen wir uns vor, Sie greifen auf einige fileService, um die Datei in einem Fire-and-Forget-Abschnitt zu laden, und Sie Mockito (oder ein anderes Mock-Framework, die Idee bleibt gleich) für Ihre Komponententests. Dann würde der Code, den ich Bezug werde in meiner Erklärung so ähnlich aussehen:

class SystemUnderTest(val fileService: MyFileService) { 
    def testedMethod(): GoodResult = { 
    val file = // ... some logic to extract file ... 
    Future { 
     fileService.uploadFile(file) 
    } 
    // ... other logic returning an instance of GoodResult 
    } 
} 

Dann in Ihrer Testmischung in org.scalatest.Eventually und eine Behauptung wie diese macht:

eventually { 
    verify(fileService).uploadFile(any()) 
} 

Es wird Stellen Sie sicher, dass der Hauptprozess nicht beendet wird, bevor sichergestellt werden kann, dass der Uploader-Dienst aufgerufen wurde (oder das durch implicit patienceConfig definierte Zeitlimit abgelaufen ist).


Und natürlich haben Sie immer die Möglichkeit, die Zukunft zurückkehren Sie in Ihrem Produktionscode nicht warten, und warten auf sie in den Tests.

Verwandte Themen