0

I have a model called Job. And I made a file services.py where I am going to put some methods and business logic. I am trying to test them using Mock. The problem is that If I want to mock Job.objects.create it, it gives me an error.

services.py

from .models import Job
class CreateJob:                                                    

    def __init__(                                                   
        self,                                                       
        title,                                                      
        email,                                                      
    ):                                                              
        self._title = title                                         
        self._email = email                                         

    def execute(self):                                              
        # Create dictionary with the keys without the first _ in the name
        params = {k[1:] if k[0] == '_' else k:v for k,v in self.__dict__.items() if v is not None}
        job = Job.objects.create(**params)
        return job

This is mi test case, and it runs OK

class TestExecute(TestCase):                     
    def setUp(self):                             
        self._use_case = CreateJob(              
            title='How to test a job creation',  
            email='[email protected]',      
        )                                        

    def test_return_job_type(self):              
        result = self._use_case.execute()        
        assert isinstance(result, Job)           

But If I want to patch the create method, so I do not hit the database, like this

def create_job(params):                                     
    return Job(**params)                                    

@patch.object(Job.objects, 'create', side_effect=create_job)
class TestExecute(TestCase):                                
    def setUp(self):                                        
        self._use_case = CreateJob(                         
            title='How to test a job creation',             
            email='[email protected]',                 
        )                                                   

    def test_return_job_type(self,mock_create):             
        result = self._use_case.execute()                   
        assert isinstance(result, Job)

I have the following error: TypeError: create_job() got an unexpected keyword argument 'title'

And here is the trace:

services.py:100: in execute
job = Job.objects.create(**params)
/usr/lib/python3.6/unittest/mock.py:939: in __call__
return _mock_self._mock_call(*args, **kwargs)
def _mock_call(_mock_self, *args, **kwargs):
    self = _mock_self
    self.called = True
    self.call_count += 1
    _new_name = self._mock_new_name
    _new_parent = self._mock_new_parent

    _call = _Call((args, kwargs), two=True)
    self.call_args = _call
    self.call_args_list.append(_call)
    self.mock_calls.append(_Call(('', args, kwargs)))

    seen = set()
    skip_next_dot = _new_name == '()'
    do_method_calls = self._mock_parent is not None
    name = self._mock_name
    while _new_parent is not None:
        this_mock_call = _Call((_new_name, args, kwargs))
        if _new_parent._mock_new_name:
            dot = '.'
            if skip_next_dot:
                dot = ''

            skip_next_dot = False
            if _new_parent._mock_new_name == '()':
                skip_next_dot = True

            _new_name = _new_parent._mock_new_name + dot + _new_name

        if do_method_calls:
            if _new_name == name:
                this_method_call = this_mock_call
            else:
                this_method_call = _Call((name, args, kwargs))
            _new_parent.method_calls.append(this_method_call)

            do_method_calls = _new_parent._mock_parent is not None
            if do_method_calls:
                name = _new_parent._mock_name + '.' + name

        _new_parent.mock_calls.append(this_mock_call)
        _new_parent = _new_parent._mock_new_parent

        # use ids here so as not to call __hash__ on the mocks
        _new_parent_id = id(_new_parent)
        if _new_parent_id in seen:
            break
        seen.add(_new_parent_id)

    ret_val = DEFAULT
    effect = self.side_effect
    if effect is not None:
        if _is_exception(effect):
            raise effect

        if not _callable(effect):
            result = next(effect)
            if _is_exception(result):
                raise result
            if result is DEFAULT:
                result = self.return_value
            return result
           ret_val = effect(*args, **kwargs)
E           TypeError: create_job() got an unexpected keyword argument 'title'
1
  • share code of Job model Commented Mar 11, 2019 at 7:27

1 Answer 1

3

You have to define your accepted parameters for create_job method. At the moment it only accepts 1 parameter called params. You should write it this way:

def create_job(**params):                                     
    return Job(**params)

And the convenvtion for python is to use *args and **kwargs, altough it is not required to use them.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.