def dump_tests(self, filename, functions): self.collect_instances(functions) self.output_.append('') self.output_.append('') self.output_.append('class %s(unittest.TestCase):' % self.get_testname(filename)) functions = filter( lambda fn: runtime.get_code_name(fn[0]) != '__init__', functions) functions = sorted(functions, key=lambda fn: runtime.get_code_name(fn[0])) for code, function in functions: if function.calls: mocks = self.get_mocks(function) self.dump_mock_decorators(mocks) self.output_.append( indent(1) + 'def test_%s(self%s):' % (runtime.get_code_name(code), self.get_mock_args(mocks))) self.dump_mock_return_values(mocks) try: self.dump_call( filename, code, random.choice(list(function.calls.values()))) except: traceback.print_exc() self.output_.append('if __name__ == "__main__":') self.output_.append(indent(1) + 'unittest.main()\n')
def dump_call(self, filename, code, call): definer, member = self.get_defining_item(code) for (args, return_value) in call: func_self = args.get('self') is_func = inspect.isfunction(member) is_method = inspect.ismethod(member) is_static = isinstance(definer.__dict__.get(runtime.get_code_name(code)), staticmethod) is_mod = isinstance(definer, types.ModuleType) if isinstance(member, property) or inspect.ismethod(member): if not is_static: typename, init, init_args = self.get_instance(self.instances, func_self) if typename == "NoneType": self.output_.append(''.join([ indent(2), 'pass\n\n' ])) continue self.dump_create_instance(typename, init, init_args) if 'self' in args: del args['self'] target = '%s_instance' % typename.lower() else: target = definer.__name__ else: self.add_import(filename) target = definer.__name__ # Useful for debugging # print '-' * 80 # print 'call: ', call # print 'definer:', definer # print 'member: ', member # print 'target: ', target # print 'name: ', runtime.get_code_name(code) # print 'ismod?: ', is_mod # print 'static?:', is_static # print 'method?:', is_method # print 'func?: ', is_func # print '-' * 80 call = '%s.%s' % (target, runtime.get_code_name(code)) if is_method or is_func or is_static or is_mod: call += '(%s)' % ( ','.join(['%s=%s' % (k, repr(v)) for k, v in list(args.items())]), ) call += ',\n' self.output_.append(''.join([ indent(2), 'self.assert%s(\n' % self.get_assert(return_value), indent(3), call, indent(3), '%s\n' % self.get_assert_value(return_value), indent(2), ')\n' ])) self.output_.append('') break
def dump_call(self, filename, code, call, mocks): output_ = [] definer, member = self.get_defining_item(code) if mocks: output_ += self.dump_mock_decorators(mocks, definer.__name__) output_.append( indent(1) + 'def test_%s(self%s):' % (runtime.get_code_name(code), self.get_mock_args(mocks))) output_ += self.dump_mock_return_values(mocks) else: output_.append( indent(1) + f'def test_{runtime.get_code_name(code)}_{"".join(random.choices(string.ascii_letters + string.digits, k=4))}(self):' ) before_args, return_value, after_args = call self.add_import(filename) target = definer.__name__ # Useful for debugging logger.debug('-' * 80) logger.debug(f'call: {call}') logger.debug(f'definer: {definer}') logger.debug(f'member: {member}') logger.debug(f'target: {target}') logger.debug(f'name: {runtime.get_code_name(code)}') logger.debug('-' * 80) print(before_args) for k, v in before_args.items(): output_.append( indent(2) + f'arg_{k} = {self._write_descrialize(v)}') call = indent(2) + 'actual_ret = %s.%s' % (target, runtime.get_code_name(code)) call += '(%s)' % (','.join( [f'{k}=arg_{k}' for k in before_args.keys()]), ) output_.append(call) output_.append('') output_.append(indent(2) + '# check return value') output_ += self._assert_equals(self._write_descrialize(return_value), 'actual_ret', return_value.type_name) if after_args.items(): output_.append(indent(2) + '# check parameter mutation') for k, v in after_args.items(): if not inspect.iscode(v): output_.append( indent(2) + f'expected_arg_{k} = {self._write_descrialize(v)}') output_ += self._assert_equals(f'expected_arg_{k}', f'arg_{k}', v.type_name) output_.append('') return output_
def init_function(self, functions): self.class_params = {} function = None for fn in functions: if runtime.get_code_name(fn[0]) == '__init__': code, function = fn break if function: for _, calls in function.calls.items(): for (args, _) in calls[:1]: func_self = args['self'] func_self_type = func_self.__class__ func_self_type = str(func_self_type) func_self_type = func_self_type.replace("<class '", "") func_self_type = func_self_type.replace("'>", "") if "." in func_self_type: func_self_type = func_self_type[func_self_type.find(".")+1:] self.class_params[func_self_type] = "(" for key, value in args.items(): if key != 'self': if type(value) == str: self.class_params[func_self_type] += "\"" + str(value) + "\"," else: self.class_params[func_self_type] += str(value) + "," self.class_params[func_self_type] += ")"
def dump_mock_decorators(self, mocks): last_position = len(self.output_) for (code, mock) in mocks: definer, member = self.get_defining_item(code) self.add_import('mock', 'patch') self.output_.insert(last_position, indent(1) + '@patch.object(%s, \'%s\')' % ( self.get_declared_module_name(definer.__name__), runtime.get_code_name(code)))
def dump_mock_decorators(self, mocks): if mocks: self.add_import('unittest.mock', 'patch') for (code, mock) in reversed(mocks): definer, member = self.get_defining_item(code) self.output_.append( indent(1) + '@patch.object(%s, \'%s\')' % (self.get_declared_module_name(definer.__name__), runtime.get_code_name(code)))
def dump_mock_return_values(self, mocks): output_ = [] for (code, mock_function) in mocks.items(): _, return_value, _ = list(mock_function.calls)[0] output_.append( indent(2) + 'mock_%s.return_value = %s' % (runtime.get_code_name(code), self._write_descrialize(return_value))) return output_
def dump_tests(self, filename, functions): self.output_.append('') self.output_.append('') self.output_.append('class %s(unittest.TestCase):' % self.get_testname(filename)) functions = filter( lambda fn: runtime.get_code_name(fn[0].f_code) != '__init__', functions) functions = sorted(functions, key=lambda fn: runtime.get_code_name(fn[0].f_code)) for frame, function in functions: print("Dumping", frame, function) for call in function.calls: self.output_ = self.output_ + self.dump_call( filename, frame.f_code, call, function.mocks) self.output_.append('') self.output_.append('if __name__ == "__main__":') self.output_.append(indent(1) + 'unittest.main()\n')
def _write_descrialize(self, v): if inspect.iscode(v): return 'mock_%s' % runtime.get_code_name(v) if v.direct: return repr(self.configs['converter'].deserialize(v[0], v[1])) else: # TODO this part is so bad, improve it using (maybe) suggestions here https://stackoverflow.com/a/38839418/4237785 move(v[1], os.path.join(self.configs['output_path'], 'fixtures', v[1])) return f'{self.converter}.deserialize({DefaultGenerator._quote(v[0])}, {DefaultGenerator._quote(os.path.join("tests", "fixtures", v[1]))})'
def dump_mock_return_values(self, mocks): for (code, mock) in mocks: args, return_value = list(mock.calls.values())[0][0] if not self.is_object(return_value): return_value = repr(return_value) else: instance = self.get_instance(self.instances, return_value) if instance: return_value = self.get_initializer(*instance) else: return_value = "None # TODO: fix mock for %s()" % return_value self.output_.append(indent(2) + 'mock_%s.return_value = %s' % (runtime.get_code_name(code), return_value))
def collect_instances(self, functions): for code, function in [fn for fn in functions if runtime.get_code_name(fn[0]) == '__init__']: for _, calls in list(function.calls.items()): for (args, _) in calls[:1]: func_self = args['self'] func_self_type = func_self.__class__ for base in func_self.__class__.__bases__: for _, init in [member for member in inspect.getmembers(base) if member[0] == '__init__']: if getattr(init, "__code__", None) == code: func_self_type = base mod = func_self_type.__module__ self.add_import(mod, func_self_type.__name__) self.instances[self.get_object_id(type(func_self), func_self)] = (func_self_type.__name__, code, args)
def collect_instances(self, functions): for code, function in filter( lambda fn: runtime.get_code_name(fn[0]) == '__init__', functions): for (args, _, _) in function.calls[:1]: func_self = args['self'] func_self_type = func_self.__class__ for base in func_self.__class__.__bases__: for _, init in filter( lambda member: member[0] == '__init__', inspect.getmembers(base)): if getattr(init, "__code__", None) == code: func_self_type = base mod = func_self_type.__module__ self.add_import(mod, func_self_type.__name__) self.instances[self.get_object_id( type(func_self), func_self)] = (func_self_type.__name__, code, args)
def collect_instances(self, functions): for code, function in filter( lambda fn: runtime.get_code_name(fn[0]) == '__init__', functions): for _, calls in function.calls.items(): for (args, _) in calls[:1]: func_self = args['self'] func_self_type = func_self.__class__ for base in func_self.__class__.__bases__: # For Python3 compatibility as __bases__ returns <class 'object'> whereas # Python2 does not return anything if isinstance(base, object): base = func_self_type for _, init in filter( lambda member: member[0] == '__init__', inspect.getmembers(base)): if getattr(init, "__code__", None) == code: func_self_type = base mod = func_self_type.__module__ self.add_import(mod, func_self_type.__name__) self.instances[self.get_object_id( type(func_self), func_self)] = (func_self_type.__name__, code, args)
def get_mock_args(mocks): return ''.join([ ', mock_%s' % runtime.get_code_name(code) for (code, mock) in mocks ])
def dump_call(self, filename, code, call): definer, member = self.get_defining_item(code) for (args, return_value) in call: func_self = args.get('self') is_func = inspect.isfunction(member) is_method = inspect.ismethod(member) is_static = isinstance(definer.__dict__.get(runtime.get_code_name(code)), staticmethod) is_mod = isinstance(definer, types.ModuleType) if isinstance(member, property) or inspect.ismethod(member): if not is_static: typename, init, init_args = self.get_instance(self.instances, func_self) if typename == "NoneType": self.output_.append(''.join([ indent(2), 'pass\n\n' ])) continue self.dump_create_instance(typename, init, init_args) if 'self' in args: del args['self'] target = "_instance" else: target = definer.__name__ else: self.add_import(filename) target = definer.__name__ if PYTHON3: if 'self' in call[0][0]: del call[0][0]['self'] name = runtime.get_code_name(code) # Useful for debugging # print ('-' * 80) # print ('call: ', call) # print ('definer:', definer) # print ('member: ', member) # print ('target: ', target) # print ('code: ', code) # print ('name: ', name) # print ('ismod?: ', is_mod) # print ('static?:', is_static) # print ('method?:', is_method) # print ('func?: ', is_func) # print ('-' * 80) ####################### if name.startswith("__") and name not in self.functions_to_avoid: name = "_" + target[:target.find("(")] + name call = '%s.%s' % (target, name) if is_method or is_func or is_static or is_mod: call += '(%s)' % ( ','.join(['%s=%s' % (k, repr(v)) for k, v in args.items()]), ) call += ',\n' self.output_.append(''.join([ indent(2), 'self.assert%s(\n' % self.get_assert(return_value), indent(3), call, indent(3), '%s\n' % self.get_assert_value(return_value), indent(2), ')\n' ])) self.output_.append('') break