2016-04-08 10 views
2

Ich habe eine Methode unter Test, der wie folgt aussieht:Mock eine Instanzmethode mit einem bestimmten Rückgabewert?

def execute_update(self): 
    """Execute an update.""" 
    p = subprocess.Popen(['command'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

    try: 
     stdout, stderr = p.communicate() 

     if p.returncode == 0: 
      # successful update, notify 
      self.logger.info("Successfully updated.") 
     else: 
      # failed update, notify 
      self.logger.error("Unable to update (code {returncode}):\n{output}".format(
       returncode=p.returncode, output=stdout)) 

    except KeyboardInterrupt as e: 
     # terminate the process 
     p.terminate() 
     raise e 

Ich versuche, mit mock ihren Aufruf von Popen und seinen Aufruf der Logging-Funktionen in einem unittest.TestCase Testverfahren zu testen:

@mock.patch.object(subprocess.Popen, 'communicate', autospec=True) 
@mock.patch('updateservice.subprocess.Popen', autospec=True) 
def test_fetch_metadata(self, mock_popen, mock_communicate): 
    """Test that we can fetch metadata correctly.""" 
    mock_communicate.return_value = ("OUT", "ERR") 
    mock_popen.returncode = 0 

    self.reference.execute_update() 

    # other asserts 

Die letzte Zeile nicht mit:

stdout, stderr = p.communicate() 
ValueError: need more than 0 values to unpack 

Was mache ich falsch? Ich habe folgende Anforderungen:

  1. -Test, dass der Konstruktor subprocess.Popen mit den richtigen Werten aufgerufen wurde.
  2. Testen Sie, dass die Protokollierungsaufrufe mit dem Ausgabe- und Rückgabecode des Prozesses ausgeführt werden.

Nummer zwei ist leicht genug, ich bin die Injektion nur ein MagicMock als Logger-Objekt, aber ich "m Probleme, mit der Nummer eins.

+0

Versuchen Sie, den 'return_value' in Ihrer Zeile' @ mock.patch.object' zu setzen. – kindall

+0

Versucht, denselben Fehler. –

+0

wie es in dem Fehler gesagt wird, fangen Sie zwei Werte in der Rückgabe ... deshalb muss Ihr return_value ein Tupel sein zB. (0,0) – Aquiles

Antwort

2

Ich denke, das Hauptproblem von Ihrem Patch-Objekt kommt hier :

@mock.patch.object(subprocess.Popen, 'communicate', autospec=True) 

Seltsamer, wie die Art von Mock scheint es, die erstellt wird, ist:

<class 'unittest.mock.NonCallableMagicMock'> 

Dies ist das erste Mal Ich habe vor über eine NonCallableMagicMock Art kommen, aber bei den minimalen Informationen sucht ich auf diese gefunden, die Dokumentation angeben this:

Der Teil, der eine Fahne für mich aufwirft, ist hier:

mit Ausnahme von return_value und side_effect, die keine Bedeutung auf einem nicht aufrufbaren Schein haben.

Es würde weitere Untersuchung erfordern, um zu bestimmen, was genau das bedeutet. Unter dass in der Prüfung, und vielleicht haben Sie dies bereits versucht, die folgende Änderung Ihre Unittest Ausbeuten erfolgreich spöttische Ergebnisse:

@mock.patch('server.upd.subprocess.Popen', autospec=True) 
def test_fetch_metadata(self, mock_popen): 
    """Test that we can fetch metadata correctly.""" 

    mock_popen.return_value = Mock() 
    mock_popen_obj = mock_popen.return_value 

    mock_popen_obj.communicate.return_value = ("OUT", "ERR") 
    mock_popen_obj.returncode = 0 

    self.reference.execute_update() 

So, wie Sie sehen können, sind wir so ziemlich unser Mock-Objekt erstellen pro den mock_popen.return_value . Von da an stimmt alles andere ziemlich genau mit dem überein, was Sie getan haben.

Verwandte Themen