1

When I use the following code:

from unittest import mock import configparser configtext = ''' [SECTION] whatever=True ''' config = configparser.ConfigParser() config.read_string(configtext) def test_fails(): expected_value = 'fnord' with mock.patch.dict(config, {'db': expected_value}): assert config['db'] is expected_value 

My test fails because AttributeError: 'str' object has no attribute 'items'.

This is not at all what I expected. Obviously I would expect it to set the value like I want... but apparently config is only dict-ish, unfortunately.

How can I patch this so config['db'] is the value I want, just for the lifetime of my test?

6
  • 2
    What are you actually trying to test, here? Commented Feb 29, 2016 at 22:09
  • @jonrsharpe I'm actually doing something else, but this is the most MVCE ;) Commented Feb 29, 2016 at 22:17
  • Well then it's not a terribly helpful example! Please give a minimal reproducible example of the code under test, too. Commented Feb 29, 2016 at 22:20
  • The code under test is not failing - the mock.patch.dict call is failing. Commented Feb 29, 2016 at 22:22
  • 2
    You're calling mock.patch.dict, but config is not a dictionary (and it's barely dictionary-like). If you would stop being cagey about what you're actually trying to test we might be able to provide suggestions about better ways to go about it. In this situation, it's not clear why you're even using mock (just set the option in the config object!). Commented Feb 29, 2016 at 22:25

1 Answer 1

2

It appears that the problem is that I had a slight misunderstanding. Although ConfigParser looks dict-like, it isn't actually. The stack trace holds evidence of this:

 def test_fails(): expected_value = 'whatever' > with mock.patch.dict(config, {'db': expected_value}): test.py:15: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.5/unittest/mock.py:1593: in __enter__ self._patch_dict() /usr/lib/python3.5/unittest/mock.py:1619: in _patch_dict in_dict[key] = values[key] /usr/lib/python3.5/configparser.py:969: in __setitem__ self.read_dict({key: value}) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <configparser.ConfigParser object at 0x7f1be6d20f98>, dictionary = {'db': 'whatever'} source = '<dict>' 

Note that it's trying to do a read_dict here. That's because it's expecting to have a section-ish format:

>>> parser = configparser.ConfigParser() >>> parser.read_dict({'section1': {'key1': 'value1', ... 'key2': 'value2', ... 'key3': 'value3'}, ... 'section2': {'keyA': 'valueA', ... 'keyB': 'valueB', ... 'keyC': 'valueC'}, ... 'section3': {'foo': 'x', ... 'bar': 'y', ... 'baz': 'z'} ... }) 

From the docs

Having a single-key access is not possible. To get this example to work, you have to do the following:

with mock.patch.dict(config, {'db': {'db': expected_value}}): # rest of code 

Note: Values will be converted to their stringish counterparts. So if you are trying to store an actual database connection (or similar) here, it won't work.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.