Migrating from pocha to pytest
molten-firescar96 opened this issue · 0 comments
molten-firescar96 commented
I started using pocha 2 years ago shortly after it went out of active development. I just got around to migrating from it to pytest (with pytest-asyncio and pytest-mocha). In case someone else is in the same situation here is the script I wrote to migrate my test files. No citation needed for its use.
import os
import re
from collections import OrderedDict
from utilities import convert_to_camel_case
input_file = 'base.py'
input_file = os.path.join('test/', input_file)
with open(input_file) as f:
input_data = f.read()
output = OrderedDict()
output['root'] = []
output['root'].append('import pytest')
skip_lines = 0
test_name = None
test_subsection = ['root']
has_before_each = {}
for line in input_data.split('\n'):
# if a previous statement wants to skip lines then do it
if skip_lines:
skip_lines -= 1
continue
# ignore our custom decorator
if 'make_sync_from_async' in line:
continue
# skip empty lines because they cause problems when deciding when to unindent
line_sans_leading_spaces = re.sub(r'\s', '', line)
if not line_sans_leading_spaces:
output[test_subsection[-1]].append('')
continue
# ignore commented out code blocks
if re.match(r'\s*#', line):
output[test_subsection[-1]].append(line)
continue
# replace pocha with unitttest, but only once
added_imports = False
if 'from pocha import' in line:
if not added_imports:
output[test_subsection[-1]].append('from unittest import TestCase')
continue
# these values will be useful later
extra_space, = re.match(r'(\s*)', line).groups()
spacing = int(extra_space.count(' ')/4)
describe_match = re.match(r".*@describe\('(.*)'\)", line)
before_match = re.match('.*@before_each', line)
after_match = re.match('.*@after_each', line)
# replace describe statements
if describe_match:
class_name, = describe_match.groups()
class_name = class_name.replace('tests', '').replace('test', '').strip().replace(' ', '_').capitalize()
class_name = convert_to_camel_case(class_name)
test_subsection.append(class_name)
output[test_subsection[-1]] = []
output[test_subsection[-1]].append('class Test' + class_name + '(TestCase):')
mocha_name = ' :: '.join(test_subsection[1:])
output[test_subsection[-1]].append(" '''" + mocha_name + "'''")
skip_lines = 1
continue
# if the spacing decreases then we need to pop out of the subsection
should_unindent = spacing < (len(test_subsection)-1)
if should_unindent:
test_subsection = test_subsection[:-1]
# unittest doesn't use nesting like pocha does, so we need to remove spaces from the previous code
indent = len(test_subsection)-2
if indent > 0:
extra_space = ' '*indent*4
line = re.sub('^'+extra_space, '', line)
# replace before_each statements
if before_match or (after_match and test_subsection[-1] not in has_before_each):
has_before_each[test_subsection[-1]] = True
output[test_subsection[-1]].append(' @pytest.fixture(autouse=True)')
output[test_subsection[-1]].append(' @pytest.mark.asyncio')
output[test_subsection[-1]].append(' async def setup(self):')
skip_lines = 2
if before_match:
continue
# replace after_each statements
if after_match:
output[test_subsection[-1]].append(' try:')
output[test_subsection[-1]].append(' yield')
output[test_subsection[-1]].append(' except:')
output[test_subsection[-1]].append(' pass')
skip_lines = 1
continue
# replace it statements
match = re.match(r".*@it\((.*)\)", line)
if match:
test_name, = match.groups()
test_name = test_name.strip().strip("'").replace("\\'", '')
# remove other arguments
test_name = re.sub(r',.*skip=True.*', '', test_name)
if 'skip=True' in line:
output[test_subsection[-1]].append(' @pytest.mark.skip(reason="no way of testing this")')
continue
# modify the functions for it statements to support pytest-mocha
if re.match('.*def _\(', line):
if not test_name:
continue
if 'async def' in line:
output[test_subsection[-1]].append(' @pytest.mark.asyncio')
function_name = 'test_' + re.sub('[ -/,]', '_', test_name)
line = re.sub(r'_\(.*', function_name + '(self):', line)
# print(line)
output[test_subsection[-1]].append(line)
output[test_subsection[-1]].append(" '''{a}'''".format(a=test_name))
test_name = None
continue
output[test_subsection[-1]].append(line)
output_path, output_file = os.path.split(input_file)
output_file = output_path + '/test_' + output_file
print('pytest -W ignore -k ' + input_file)
with open(output_file, 'w') as f:
for k, v in output.items():
f.write('\n'.join(v))
f.write('\n\n')