سؤال

I'm trying to run unit tests on a class that imports two other modules, and I'm trying to patch out those modules using mock. One of these modules is instantiated in the class I'm testing, and I have not been able to patch it out. It appears that I have managed to patch out the other one.

What is the best way to patch out the sequence.processor module in this code?

Directory structure

logger.py
parser/
    __init__.py
    docparser.py
sequence/
    __init__.py
    processor.py
tests/
    testdocparser.py

/parser/docparser.py

import logger
from sequence.processor import Processor

class DocParser(object):
    def __init__(self, reader_writer):
        self.processor = Processor(reader_writer)

    def write_and_parse(self, products):
        logger.log(products)
        self.processor.process(products)

/tests/testdocparser.py

import unittest
from mock import MagicMock, patch

from parser import docparser

class DocParserTests(unittest.TestCase):
    def setUp(self):
        self.mock_writer = MagicMock()
        self.docparser = docparser.DocParser(self.mock_writer)

    @patch("parser.docparser.logger") # This seems to be patched properly
    @patch("parser.docparser.Processor") # This is not patched
    def test_write_and_parse(self, mock_logger, mock_proc):
        products = "products"
        self.docparser.write_and_parse(products)
هل كانت مفيدة؟

المحلول

You patch Processor in test_write_and_parse() but it's instantiated in DocParser.__init__() which is called from setUp().

This should work, though I haven't tested it:

class DocParserTests(unittest.TestCase):
    def setUp(self):
        self.mock_writer = MagicMock()
        with patch('parser.docparser.Processor'):
            self.docparser = docparser.DocParser(self.mock_writer)

    @patch("parser.docparser.logger")
    def test_write_and_parse(self, mock_logger):
        products = "products"
        self.docparser.write_and_parse(products)

I've used context manager instead of decorator to avoid changing setUp() signature (adding an argument).

Also the order of mock arguments for test_write_and_parse() is incorrect in your code. Here's an excerpt from mock docs:

When you nest patch decorators the mocks are passed in to the decorated function in the same order they applied (the normal python order that decorators are applied). This means from the bottom up...

Correct order:

@patch("parser.docparser.logger") # This seems to be patched properly
@patch("parser.docparser.Processor") # This is not patched
def test_write_and_parse(self, mock_proc, mock_logger):
   # ...

Of cource, it doesn't really matter in your particular case because mock_proc and mock_logger are not used later.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top