I have some python code and I want to coverage it with unittest.
My simple code is:
import os
import glob
class GitRepoParser:
def __init__(self, repo_dir: str):
self.repo_dir = repo_dir
def get_folder_path(self, service_name: str) -> str:
dir_path = '{path}/configuration/settings/{name}'.format(
path=self.repo_dir,
name=service_name
)
return dir_path
def create_new_service(self, service_name: str, service_version: str):
dir_path = self.get_folder_path(service_name)
if os.path.isdir(dir_path):
return
os.makedirs(dir_path)
property_file = '{folder}/{name}-deployment.properties'.format(
folder=dir_path,
name=service_name
)
current_path = os.path.dirname(__file__)
template_path = os.path.join(
current_path, '..', 'file_templates/deployment.properties'
)
if not os.path.isfile(template_path):
return
template_file = open(template_path, 'r')
with open(property_file, 'w') as properties:
for line in template_file:
# Create parser for this code part
value = line.strip().replace(
'%service_name%', service_name
)
properties.write(value + '\n')
template_file.close()
Help me to create some unittest for this lines of code. I create some class GitRepoParserTest in my python tests:
class GitRepoParserTest(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
self.parser = GitRepoParser('/path-to-download')
def test_get_folder_path(self):
folder_path = self.parser.get_folder_path(service_name='oleg-service')
self.assertIsInstance(folder_path, str)
def test_create_new_service(self):
pass
But I don't understand how I need to write tests for create_new_service function.
Please help me.
Thank you.
Here is the unit test solution for Python 3.7.5:
test_GitRepoParser.py:
import unittest
from unittest.mock import Mock, patch, mock_open, call
from GitRepoParser import GitRepoParser, os
class GitRepoParserTest(unittest.TestCase):
def setUp(self):
self.parser = GitRepoParser('/path-to-download')
self.mock_open = mock_open(read_data='some data')
def test_get_folder_path(self):
folder_path = self.parser.get_folder_path(service_name='oleg-service')
self.assertIsInstance(folder_path, str)
#patch('GitRepoParser.os')
def test_create_new_service_read_and_write_file_correctly(self, mock_os):
mock_path = Mock()
mock_path.dirname.return_value = '/Users/foo'
mock_path.isdir.return_value = False
mock_path.join.return_value = '/Users/whatever'
mock_path.isfile.return_value = True
mock_os.path = mock_path
mock_os.makedirs = Mock()
with patch('GitRepoParser.open', self.mock_open):
self.parser.create_new_service(service_name='oleg-service', service_version='1.0')
mock_path.isdir.assert_called_with('/path-to-download/configuration/settings/oleg-service')
mock_os.makedirs.assert_called_with('/path-to-download/configuration/settings/oleg-service')
expected = [call('/Users/whatever', 'r'),
call('/path-to-download/configuration/settings/oleg-service/oleg-service-deployment.properties', 'w')]
self.mock_open.assert_has_calls(expected)
handle = self.mock_open()
handle.write.assert_called()
handle.close.assert_called_once()
#patch('GitRepoParser.os')
def test_create_new_service_do_nothing_if_dir_path_is_dir(self, mock_os):
mock_path = Mock()
mock_path.isdir.return_value = True
mock_os.path = mock_path
mock_os.makedirs = Mock()
self.parser.create_new_service(service_name='oleg-service', service_version='1.0')
mock_path.isdir.assert_called_with('/path-to-download/configuration/settings/oleg-service')
mock_os.makedirs.assert_not_called()
if __name__ == '__main__':
unittest.main()
Unit test result with coverage report:
...
----------------------------------------------------------------------
Ran 3 tests in 0.023s
OK
Name Stmts Miss Cover Missing
--------------------------------------------------------------------------------
src/stackoverflow/58384586/GitRepoParser.py 24 1 96% 35
src/stackoverflow/58384586/test_GitRepoParser.py 37 0 100%
--------------------------------------------------------------------------------
TOTAL 61 1 98%
As you can see, there is still a if condition branch left. You can finish it by yourself.
Source code: https://github.com/mrdulin/python-codelab/tree/master/src/stackoverflow/58384586
Related
Let's say I have following classes:
check.py:
class Build:
def __init__(self, url):
self.url = url
self.parameters = {}
class Job:
def __init__(self, builds):
self.builds = []
for build in builds:
self.builds.append(build)
def builds_filter(self, builds_filter_func):
self.builds = [build for build in self.builds if builds_filter_func(build)]
def build_filter_according_to_name(job, name):
job.builds_filter((lambda build: build.parameters.get("NAME", "") == name))
if __name__ == '__main__':
job = Job([Build(url="url1"), Build(url="url3"), Build(url="url3")])
build_filter_according_to_name(job, "FOO")
I'd like to test in a unittest file the method build_filter_according_to_name, with different sets of parameters in each build. How do I do it?
For example:
A Job object with 5 builds, 1 of them has "NAME" == "foo".
A Job object with 5 builds, 4 of them has "NAME" == "foo".
etc.
Do I have to loop over self.builds before each test, and assign the parameters for each build, like this?
test_check.py:
import unittest
from test.check import Job, Build, build_filter_according_to_name
NAME = "FOO"
class MyTestCase(unittest.TestCase):
def setUp(self):
self.job = Job([Build(url="url1"), Build(url="url3"), Build(url="url3")])
self.parameters = {
"NAME": "NAME",
"FOO": "BAR"
}
def init_params(self, number_of_foo_names=0):
for build in self.job.builds:
parameters = self.parameters.copy()
if number_of_foo_names > 0:
parameters["NAME"] = "FOO"
number_of_foo_names -= 1
build.parameters = parameters
def test_one_name_foo(self):
self.init_params(number_of_foo_names=1)
build_filter_according_to_name(self.job, name=NAME)
self.assertEqual(len(self.job.builds), 1)
def test_two_names_foo(self):
self.init_params(number_of_foo_names=2)
build_filter_according_to_name(self.job, name=NAME)
self.assertEqual(len(self.job.builds), 2)
if __name__ == '__main__':
unittest.main()
Or is there a better way to achieve it?
I'm new in Python. I have a __init__ function with information about data sink config and I have to write some test cases fot it. But init is a function which doesn't return any result so confuses me. Can you show me some ways to implement test case for it ? Thank you.
My function :
class DataSinkConfig():
DEFAULT_ENTRIES_TABLE = 'entries'
DEFAULT_OUTLIERS_TABLE = 'outliers'
DEFAULT_OUTLIERCAUSES_TABLE = 'outlier_causes'
# Note
def __init__(self, dbconf):
insopt = dbconf.get('insopt')
if insopt is None:
self.entries_table_name = self.DEFAULT_ENTRIES_TABLE
self.outliers_table_name = self.DEFAULT_OUTLIERS_TABLE
self.outlier_causes_table_name = self.DEFAULT_OUTLIERCAUSES_TABLE
else:
try:
dict(insopt)
except Exception as e:
raise Exception(
"Invalid value {} for parameter 'insopt'.".format(insopt))
self.entries_table_name = self.__complement_item(insopt, 'entry_tbl', self.DEFAULT_ENTRIES_TABLE)
self.outliers_table_name = self.__complement_item(insopt, 'outlier_tbl', self.DEFAULT_OUTLIERS_TABLE)
self.outlier_causes_table_name = self.__complement_item(insopt, 'cause_tbl', self.DEFAULT_OUTLIERCAUSES_TABLE)
My test is stuck :
import unittest
import DataSinkConfig, DataSourceConfig
class TestDataSink(unittest.TestCase):
def setUp(self):
#pass
if __name__ == "__main__":
unittest.main()
You can do stuff like check the state on the object.
Obviously you can move DataSink instantiation to the setUp method.
import unittest
import DataSinkConfig, DataSourceConfig
class TestDataSink(unittest.TestCase):
def setUp(self):
#pass
def test_data_sink(self):
dsc = DataSinkConfig(db_conf)
self.assertEqual(dsc.entries_table_name, "WHATREVER COMPLIMENT ITEM WAS SUPPOSE TO SET")
if __name__ == "__main__":
unittest.main()
I have a class, which use a class variable to choose which logic to execute.
#in file1:
class SomeHelper():
def __init__(self):
self.my_var = 0
#in file2:
import file1
class MyClass():
...
...
def calculate():
inst = file1.SomeHelper()
if x > inst.my_var:
etc etc
I am writing a unit test and mocking SomeHelper() in another file:
from file 2 import MyClass
# tried both
#patch('file2.file1') OR #patch('file2.file1.SomeHelper')
def test_calculate(self, mock_helper):
mock_helper.my_var = 0
to_test = MyClass.calculate()
And I get the following error:
TypeError: '>' not supported between instances of 'MagicMock' and 'int'.
I thought I defined my_var after I patched the module.
Here is the unit test solution for Python 3.7.5:
file1.py:
class SomeHelper():
def __init__(self):
self.my_var = 0
file2.py:
import file1
class MyClass():
#classmethod
def calculate(cls):
x = 1
inst = file1.SomeHelper()
if x > inst.my_var:
return True
return False
test_file2.py:
import unittest
from unittest.mock import patch
from file2 import MyClass
class TestMyClass(unittest.TestCase):
#patch('file2.file1')
def test_calculate(self, mock_file1):
inst = mock_file1.SomeHelper.return_value
inst.my_var = 0.5
to_test = MyClass.calculate()
self.assertTrue(to_test)
mock_file1.SomeHelper.assert_called_once()
#patch('file2.file1')
def test_calculate_2(self, mock_file1):
inst = mock_file1.SomeHelper.return_value
inst.my_var = 2
to_test = MyClass.calculate()
self.assertFalse(to_test)
mock_file1.SomeHelper.assert_called_once()
if __name__ == '__main__':
unittest.main()
Unit test result with coverage report:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
Name Stmts Miss Cover Missing
------------------------------------------------------------------------
src/stackoverflow/50242955/file1.py 3 1 67% 3
src/stackoverflow/50242955/file2.py 8 0 100%
src/stackoverflow/50242955/test_file2.py 16 0 100%
------------------------------------------------------------------------
TOTAL 27 1 96%
Source code: https://github.com/mrdulin/python-codelab/tree/master/src/stackoverflow/50242955
I want to test this method, however I would need to mock the variable dirContent
def imageFilePaths(paths):
imagesWithPath = []
for _path in paths:
try:
dirContent = os.listdir(_path)
except OSError:
raise OSError("Provided path '%s' doesn't exists." % _path)
for each in dirContent:
selFile = os.path.join(_path, each)
if os.path.isfile(selFile) and isExtensionSupported(selFile):
imagesWithPath.append(selFile)
return list(set(imagesWithPath))
how do I just mock a variable using mox ?
This is how I have however tried to mock os.listdir
def setUp(self):
self._filePaths = ["/test/file/path"]
self.mox = mox.Mox()
def test_imageFilePaths(self):
filePaths = self._filePaths[0]
self.mox.StubOutWithMock(os,'listdir')
dirContent = os.listdir(filePaths).AndReturn(['file1.jpg','file2.PNG','file3.png'])
self.mox.ReplayAll()
utils.imageFilePaths(filePaths)
self.mox.VerifyAll()
also tried this way
def test_imageFilePaths(self):
filePaths = self._filePaths
os = self.mox.CreateMock('os')
os.listdir = self.mox.CreateMock(os)
dirContent = os.listdir(filePaths).AndReturn(['file1.jpg','file2.PNG','file3.png'])
self.mox.ReplayAll()
lst = utils.imageFilePaths(filePaths)
# self.assertEquals('/test/file/path/file1.jpg', lst[0])
self.mox.VerifyAll()
but the call to method being tested doesn't recognizes the mocked discontent
Typically you would not mock a variable, but instead mock the function call used to set that variable's value. In your example, for instance, you'd mock out os.listdir and have it return a mock value.
# Your test file
import os
class YourTest(...):
def setUp(self):
self.mox = mox.Mox()
def tearDown(self):
self.mox.UnsetStubs()
# Your test
def testFoo(self):
self.mox.StubOutWithMock(os, 'listdir')
# the calls you expect to listdir, and what they should return
os.listdir("some path").AndReturn([...])
self.mox.ReplayAll()
# ... the rest of your test
I have a config file and i want to load the options dynamicaly by entering the section and the options name.
For instance this is the config file contents.
[templates]
path = /full/path/to/template
and the config.py file
class Config(object):
def __init__(self):
self.config = ConfigParser.ConfigParser()
self.config.read('config.ini')
for section in self.config.sections():
self.__dict__[section] = dict()
for k, v in self.config.items(section):
self.__dict__[section][k] = v
def from_options(self, section, option):
if section in self.__dict__:
if option in self.__dict__[section]:
return self.__dict__[section][option]
if __name__ == '__main__':
c = Config()
print c.from_options('templates', 'path')
EDIT:
The question is if this a pythonic == right way to do it.
config.py
;# if not applicable leave it blank
[templates]
path = /full/path/to/template
configparse.py
class Config(object):
def __init__(self):
self.config = ConfigParser.ConfigParser()
self.config.read('config.py')
def get_path(self):
return self.config.get('templates', 'path')
if __name__ == '__main__':
c = Config()
print c.get_path()
this should do the trick...