wake-up-neo.com

Verspotten von zwei Funktionen mit Patch für einen Unit-Test

Ich habe eine Funktion, die ich Unit-Test enthält, ruft zwei andere Funktionen. Ich bin nicht sicher, wie ich beide Funktionen gleichzeitig mithilfe von Patch richtig verspotten kann. Ich habe unten ein Beispiel für das gegeben, was ich meine. Wenn ich Nosetests durchführe, sind die Tests erfolgreich, aber ich bin der Meinung, dass es einen saubereren Weg dafür geben muss, und ich verstehe das Stück in Bezug auf f.close () nicht wirklich.

Die Verzeichnisstruktur sieht folgendermaßen aus:

program/
  program/
    data.py
  tests/
    data_test.py

data.py:

import cPickle

def write_out(file_path, data):
    f = open(file_path, 'wb')
    cPickle.dump(data, f)
    f.close()

data_test.py:

from mock import MagicMock, patch

def test_write_out():
    path = '~/collection'
    mock_open = MagicMock()
    mock_pickle = MagicMock()
    f_mock = MagicMock()
    with patch('__builtin__.open', mock_open):
        f = mock_open.return_value
        f.method.return_value = path
        with patch('cPickle.dump', mock_pickle):
            write_out(path, 'data')
            mock_open.assert_called_once_with('~/collection', 'wb')
            f.close.assert_any_call()
            mock_pickle.assert_called_once_with('data', f)

Ergebnisse:

$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.008s
OK
54
cnodell

Sie können Ihren Test vereinfachen, indem Sie den Patch Decorator verwenden und sie wie folgt verschachteln (standardmäßig handelt es sich um MagicMock -Objekte):

@patch('cPickle.dump')
@patch('__builtin__.open')
def test_write_out(mock_open, mock_pickle):
    path = '~/collection'
    f = mock_open.return_value
    f.method.return_value = path

    write_out(path, 'data')

    mock_open.assert_called_once_with('~/collection', 'wb')
    mock_pickle.assert_called_once_with('data', f)
    f.close.assert_any_call()

Aufrufe an eine Instanz von MagicMock geben eine neue Instanz von MagicMock zurück, sodass Sie überprüfen können, ob der zurückgegebene Wert wie jedes andere verspottete Objekt aufgerufen wurde. In diesem Fall ist f ein MagicMock mit dem Namen 'open()' (versuchen Sie, f zu drucken).

81
Matti John

Zusätzlich zu der Antwort @Matti John können Sie auch patch inside function test_write_out:

from mock import MagicMock, patch

def test_write_out():
    path = '~/collection'
    with patch('__builtin__.open') as mock_open, \
            patch('cPickle.dump') as mock_pickle:

        f = mock_open.return_value
        ...
36
Alex Lisovoy

Hier ist ein einfaches Beispiel, wie man das Auslösen von ConflictError in der Funktion create_collection Mit Mock testet:

import os
from unittest import TestCase
from mock import patch
from ..program.data import ConflictError, create_collection


class TestCreateCollection(TestCase):
    def test_path_exists(self):
        with patch.object(os.path, 'exists') as mock_method:
            mock_method.return_value = True

            self.assertRaises(ConflictError, create_collection, 'test')

Bitte sehen Sie auch Mock Docs und Michael Foord's awesome Einführung in Mock .

2
alecxe