2016-04-08 5 views
2

J'ai une méthode à l'essai qui ressemble à ceci:Mock une méthode d'instance avec une certaine valeur de retour?

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 

Je tente de tester son invocation de Popen et son invocation des fonctions d'enregistrement dans une méthode d'essai unittest.TestCase avec mock:

@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 

La dernière ligne échoue avec:

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

Qu'est-ce que je fais mal? J'ai les exigences suivantes:

  1. Test que le constructeur à subprocess.Popen a été appelé avec les bonnes valeurs.
  2. Vérifiez que les appels de journalisation s'exécutent avec le code de sortie et de retour du processus.

Le numéro deux est assez facile, je suis juste injecter un MagicMock comme l'objet enregistreur, mais je "m de la difficulté avec le numéro un.

+0

Essayez de définir 'return_value' dans votre ligne' @ mock.patch.object'. – kindall

+0

J'ai essayé cela, même erreur. –

+0

comme il est dit dans l'erreur que vous attrapez deux valeurs dans le retour ... à cause de cela, votre valeur de retour doit être un tuple, par exemple. (0,0) – Aquiles

Répondre

2

Je pense que le principal problème vient de votre objet patch ici :

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

Bizarrement, il semble que le type de simulation qui est en cours de création est:

<class 'unittest.mock.NonCallableMagicMock'> 

C'est la première fois Je suis venu dans un type NonCallableMagicMock avant, mais en regardant les informations minimales que je trouve sur ce point, la documentation précise this:

La partie qui soulève un drapeau pour moi est ici:

à l'exception de return_value et side_effect qui n'ont aucun signifiant sur un simulacre non appelable.

Il faudrait un examen plus approfondi pour déterminer ce que cela signifie exactement. Prendre que pour considération, et peut-être que vous avez essayé déjà, les modifications suivantes à vos rendements unittest résultats moqueurs avec succès:

@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() 

Donc, comme vous pouvez le voir, nous sommes à peu en train de créer beaucoup notre objet fantaisie par la mock_popen.return_value . De là, tout le reste correspond à peu près à ce que vous faisiez.