### Dynamically generating test classes and test cases (nosetest and unittest compatible)
#!/usr/bin/env python3
import os
import unittest
# TODO: tests are maybe brittle due to whitespace sensitivity: regex?
def create_in_method(target_string, data):
"""do not include 'test' in the method name here otherwise nose will try to run it,
assumes class inheritance from unittest.TestCase (for assertIn)"""
def test(self):
self.assertTrue(target_string in data)
return test
# Begin the global parts so that nosetests and unittest can compatibly run
data_file = os.environ.get('TEST_DATA_FILE', 'build.log')
with open(data_file) as f:
data = f.read()
test_cases = dict()
# TODO: refactor to parse from a data file each test class, test name and test string
tests = dict()
test_string = 'tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN'
tests['test_listening_on_port_22'] = create_in_method(test_string, data)
test_string = '/usr/sbin/sshd'
tests['test_sshd_ps_exists'] = create_in_method(test_string, data)
test_cases['test_sshd_installation'] = tests
tests = dict()
test_string = 'tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN'
tests['test_listening_on_port_25'] = create_in_method(test_string, data)
test_string = '/usr/lib/postfix/master'
tests['test_postfix_ps_exists'] = create_in_method(test_string, data)
test_cases['test_mail_postfix_installation'] = tests
for test_case_name, tests in test_cases.items():
globals()[test_case_name] = type(test_case_name, (unittest.TestCase, ), tests)
if __name__ == '__main__':
# python -m unittest test_build ... OR
# nosetests --verbose --with-xunit --xunit-file=results.xml test_build.py
unittest.main(verbosity=2)
- - -
### Python Unit Tests that can be built from a domain specific language like data file
import time
import unittest
# tests will be attached to the Class dynamically
class TestCases(unittest.TestCase):
pass
def make_function(name, strings, data):
def test(self):
for s in strings:
self.assertIn(s, data, name)
return test
if __name__ == '__main__':
"""
execute using: python test_data_assertions.py
DATA FORMAT DEFINITION
# starts with a hash means a section of tests and the name should only contain ascii letters
each line represents a string that should be in the data file
TODO: ! at the beginning of a line means the data file should not contain the string
"""
# TODO: not compatible with nosetests so no junit xml =(
# e.g. nosetests --verbose --with-xunit --xunit-file=results.xml test_some_log.py
# https://nose.readthedocs.org/en/latest/writing_tests.html#test-generators
# http://eli.thegreenplace.net/2014/04/02/dynamically-generating-python-test-cases
# http://programming.nullanswer.com/question/24709208
# TODO: get data file and test files from the CLI
data_file = 'my.log'
with open(data_file) as f:
data = f.read()
tests_file = 'build.tests'
test_names = dict()
with open(tests_file) as f:
for line in f:
if line.startswith('#'):
raw_name = line[1:].strip()
name = raw_name.replace(' ', '_')
test_names['test_' + name] = list()
tests = list()
tests.append('SELECT COUNT(*) FROM accounts; 1')
tests.append('SELECT COUNT(*) FROM users; 1')
test_names['test_default_account_and_user_in_MySQL'] = tests
print('DEBUG')
for test_name, assertions in test_names.items():
print(test_name)
for i in assertions:
print(' {}'.format(i))
time.sleep(1)
for test_name, assertions in test_names.items():
test_function = make_function(test_name, assertions, data)
setattr(TestCases, test_name, test_function)
unittest.main(verbosity=2)
- - -
### Nosetests compatible version
import unittest
class TestCases(unittest.TestCase):
pass
def create_method(a, b):
"""do not include 'test' in the method name here otherwise nose will try to run it"""
def dynamic_method(self):
self.assertEqual(a, b)
return dynamic_method
dynamic_method = create_method(1,1)
dynamic_method.__name__ = 'test_{0}'.format('1_equals_1')
setattr(TestCases, dynamic_method.__name__, dynamic_method)
# remove the global dynamic_method since we only want to run those injected into TestCases
del dynamic_method
if __name__ == '__main__':
# python -m unittest test_build ... OR
# nosetests --verbose --with-xunit --xunit-file=results.xml test_build.py
unittest.main()
- - -
### Nosetests generator
> note this eschews class names and the in_data.description should be from a dict of tests
import os
data_file = os.environ.get('TEST_DATA_FILE', 'build.log')
with open(data_file) as f:
data = f.read()
def in_data(target_string, data):
assert(target_string in data)
def test_sshd_installation():
for s in [
'tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN',
'/usr/sbin/sshd'
]:
in_data.description = 'test_string_in_data'
yield in_data, s, data