2016-09-29 5 views
3

Versuchen, grundlegende Code-Tests mit Elixier zu lernen und haben Schwierigkeiten, meinen Kopf rund um Async-Funktionen zu testen (genserver's handle_info und Cast).GenServer Async-Integrationstest

Eine Möglichkeit, die funktioniert, aber sich falsch anfühlt, ist die Verwendung von :timer.sleep(x) nach Async-Funktionen.

Stellen Sie sich zum Beispiel handle_cast vor, die eine Liste von Nachrichten vom Status verarbeitet und Anrufe an ein anderes Modul abruft, das Daten von der externen API holt und nach dem Senden Nachrichten (API-Daten) an denselben Genserver zurücksendet.

Was wäre der beste Weg, dies zu testen? Kann ich Genserver-Nachrichten/Mailbox innerhalb des Tests überwachen?

edit: Ein weiteres Beispiel, sagen in init mache ich das Ausgangszustand von db zu erhalten:

Process.send_after(self(), :started, 0) 

Und: der Autor sieht aus wie:

defhandleinfo :started, state: state, do: new_state(UserServerStarted.get_data(state)) 

Muss ich andere Option dann: timer.sleep um zu überprüfen, ob UserServerStarted korrektes Ding zurückgegeben hat? Ich weiß, dass ich das Modul/die Einheit separat testen könnte, aber ich möchte einen vollständigen Integrationstest machen.

Hier ist, wie ich es jetzt tue:

... SETUP - Supervisor start UserServer... 

    test "spin up server and inital tree after user registers", % 
    {user: user} do 
    :timer.sleep(500) 
    assert %{"default" => [nil]} == GenServer.call(UserServer.via_tuple(user.id), :get) 
    end 
+0

Sie Mailbox-Nachrichten erhalten können mit 'Process.info (pid ,:: messages) 'aber das würde mit GenServer nicht zuverlässig funktionieren, da der GenServer die Nachricht verarbeiten würde, sobald sie sie empfängt, es sei denn, sie ist damit beschäftigt, eine vorherige Nachricht zu bearbeiten. – Dogbert

Antwort

2

Ich habe mit einem ähnlichen Problem in letzter Zeit zu kämpfen. Ich schaffte es zu arbeiten, indem sie den Prozess der Registrierung, dass ich den Überblick über in Tests behalten möchten:

defmodule Foo 
    def bar do 
    pid = spawn fn -> consume(channel, tag, payload) end 
    if !Process.whereis(:worker) do 
     Process.register(pid, :worker) 
    end 
    end 
end 

Und im Test:

test "bar" do 
    # < Setup code that triggers your process under test goes here > 

    # I put this here because I noticed that sometimes the process would not be 
    # fast enough to be registered - this was a quick fix. 
    :timer.sleep(100) 

    ref = Process.monitor(Process.whereis(:worker)) 

    # assert_receive will block the test until your registered process exits, 
    # or 10 seconds have passed (then something is wrong with the external service perhaps and the test will fail) 
    assert_receive {:DOWN, ^ref, :process, _, :normal}, 10000 

    # At this point the process has exited, continue with whatever assertions you want to make 
end 
Verwandte Themen