简体   繁体   中英

Unit testing file write in Python

I am writing a wrapper for the ConfigParser in Python to provide an easy interface for storing and retrieving application settings.

The wrapper has two methods, read and write , and a set of properties for the different application settings.

The write method is just a wrapper for the ConfigParser 's write method with the addition of also creating the file object needed by the ConfigParser . It looks like this:

def write(self):
    f = open(self.path, "w")
    try:
        self.config_parser.write(f)
    finally:
        f.close()

I would like to write a unit test that asserts that this method raises an IOError if the file could not be written to and in the other case that the write method of the config parser was called.

The second test is quite easy to handle with a mock object. But the open call makes things a little tricky. Eventually I have to create a file object to pass to the config parser. The fact that a file will actually be created when running this code doesn't make it very useful for a unit test. Is there some strategy for mocking file creation? Can this piece of code be tested in some way? Or is it just too simple to be tested?

First, you don't actually need to unit test open() , since it's pretty reasonable to assume that the standard library is correct.

Next, you don't want to do file system manipulations to get open() to generate the error you want, because then you're not unit testing, you're doing a functional/integration test by including the file system.

So you could perhaps replace open() in the global namespace with a surrogate that just raises an IOError . Though, probably need to make sure you put things back if execution continues.

But in the end, what value does the test have? There's so little in that code snippet that's your own system. Even replacing open() really just ends up being a test that says "does the try and finally statement in Python work?"

My suggestion? Just add a statement to the docstring that records your expectation. "Raises an IOError if the file can't be written." Then move on. You can add a unit test later if this method gains some complexity (and merit for testing).

Actually, only open could throw an exception in your code. The docs for write() doesn't say anything about exceptions. Possibly only a ValueError or something for a bad file pointer (as a result of open failing, which can't be the case here).

Making an IOError for open is easy. Just create the file elsewhere and open it for writing there. Or you could change the permissions for it so you don't have access.

You'd might wanna use the with statement here though, and it'll handle the closing itself.

In python 2.5 you need the first line. In later versions you don't need it.

from __future__ import with_statement # python 2.5 only

def write(self):
    with open(self.path, 'w') as f:
        self.config_parser.write(f)

The write method is guaranteed to be called if open succeeds, and won't be called if open raises an IOError . I don't know why you'd need a test to see if write was called. The code says that it does. Don't overdo your testing. ;)

Remember you don't have to test that open() or ConfigParser work—they're not part of your code—you just have to test that you use them correctly. You can monkeypatch the module with your own open(), just as for the instance attribute, and can return a mock from it that helps you test.

However, unit tests are not my only tool, and this is one function that's simple enough to analyze and "prove" that it works.

Less rigorously than mathematicians would like, I'm sure, but good enough for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM