Python unit testing code which calls OS/Module level python functions

2024/5/20 15:48:54

I have a python module/script which does a few of these

  1. At various nested levels inside the script I take command line inputs, validate them, apply sensible defaults
  2. I also check if a few directories exist

The above are just two examples. I am trying to find out what is the best "strategy" to test this. What I have done is that I have constructed wrapper functions around raw_input and os.path.exists in my module and then in my test I override these two functions to take input from my array list or do some mocked behaviour. This approach has the following disadvantages

  1. Wrapper functions just exist for the sake of testing and this pollutes the code
  2. I have to remember to use the wrapper function in the code everytime and not just call os.path.exists or raw_input

Any brilliant suggestions?

Answer

The short answer is to monkey patch these system calls.

There are some good examples in the answer to How to display the redirected stdin in Python?

Here is a simple example for raw_input() using a lambda that throws away the prompt and returns what we want.

System Under Test

$ cat ./name_getter.py
#!/usr/bin/env pythonclass NameGetter(object):def get_name(self):self.name = raw_input('What is your name? ')def greet(self):print 'Hello, ', self.name, '!'def run(self):self.get_name()self.greet()if __name__ == '__main__':ng = NameGetter()ng.run()$ echo Derek | ./name_getter.py 
What is your name? Hello,  Derek !

Test case:

$ cat ./t_name_getter.py
#!/usr/bin/env pythonimport unittest
import name_getterclass TestNameGetter(unittest.TestCase):def test_get_alice(self):name_getter.raw_input = lambda _: 'Alice'ng = name_getter.NameGetter()ng.get_name()self.assertEquals(ng.name, 'Alice')def test_get_bob(self):name_getter.raw_input = lambda _: 'Bob'ng = name_getter.NameGetter()ng.get_name()self.assertEquals(ng.name, 'Bob')if __name__ == '__main__':unittest.main()$ ./t_name_getter.py -v
test_get_alice (__main__.TestNameGetter) ... ok
test_get_bob (__main__.TestNameGetter) ... ok----------------------------------------------------------------------
Ran 2 tests in 0.000sOK
https://en.xdnf.cn/q/73345.html

Related Q&A

How do I connect/disconnect/configure a wireless network in python?

Im looking to see if there is a way to connect or disconnect to a wireless network in python, preferably a way that would work for both public and secured networks if I supplied the password. If I can …

CSRF protection on AJAX authentication in Flask

Id like to AJAXify both a login and a signup form on a site. Up to now Ive been using WTForms mainly for its built-in CSRF protetion, but for this project I didnt feel like it was worth it -- an extra …

Pandas groupby and Multiindex

Is there any opportunity in pandas to groupby data by MultiIndex? By this i mean passing to groupby function not only keys but keys and values to predefine dataframe columns?a = np.array([foo, foo,…

How to dump YAML with explicit references?

Recursive references work great in ruamel.yaml or pyyaml: $ ruamel.yaml.dump(ruamel.yaml.load(&A [ *A ])) &id001 - *id001However it (obviously) does not work on normal references: $ ruamel.yaml…

How to set a Pydantic field value depending on other fields

from pydantic import BaseModelclass Grafana(BaseModel):user: strpassword: strhost: strport: strapi_key: str | None = NoneGRAFANA_URL = f"http://{user}:{password}@{host}:{port}"API_DATASOURCES…

Cascade multiple RNN models for N-dimensional output

Im having some difficulty with chaining together two models in an unusual way. I am trying to replicate the following flowchart:For clarity, at each timestep of Model[0] I am attempting to generate an …

Pandas Flatten a list of list within a column?

I am trying to flatten a column which is a list of lists:var var2 0 9122532.0 [[458182615.0], [79834910.0]] 1 79834910.0 [[458182615.0], [9122532.0]] 2 458182615.0 [[79834910.0], [9122…

How to use libxml2 with python on macOs?

Im on OSX Lion and I have libxml2 installed (by default) and I have python installed (by default) but they dont talk to one another. Whats the simplest way to make this work on Lion?$ python -c "…

SMTP Authentication error while while sending mail from outlook using python language

import smtplibsmtpObj = smtplib.SMTP(smtp.office365.com, 587)smtpObj.ehlo()smtpObj.starttls()smtpObj.login([email protected], abcde)smtpObj.sendmail([email protected], [email protected], Subject: So l…

How do you change environment of Python Interactive on Vscode?

I recently migrated from Spyder to VScode. I created a new conda environment and used setting.json to change the environment in VScode, "python.pythonPath": "/Users/dcai/anaconda3/envs/…