9

I need to write a unit test for credential checking module looks something like below. I apologize I cannot copy the exact code.. but I tried my best to simplify as an example. I want to patch methodA so it returns False as a return value and test MyClass to see if it is throwing error. cred_check is the file name and MyClass is the class name. methodA is outside of MyClass and the return value checkedcredential is either True or False.

def methodA(username, password):
    #credential check logic here...
    #checkedcredential = True/False depending on the username+password combination
    return checkedcredential

class MyClass(wsgi.Middleware):
    def methodB(self, req): 
        username = req.retrieve[constants.USER]
        password = req.retrieve[constants.PW]
         if methodA(username,password):
            print(“passed”)
        else:
            print(“Not passed”)
            return http_exception...

The unit test I currently have looks like...

import unittest
import mock
import cred_check import MyClass

class TestMyClass(unittest.Testcase):
    @mock.patch('cred_check')
    def test_negative_cred(self, mock_A):
        mock_A.return_value = False
        #not sure what to do from this point....

The part I want to write in my unittest is return http_exception part. I am thinking of doing it by patching methodA to return False. After setting the return value, what would be the proper way of writing the unittest so it works as intended?

James C.
  • 501
  • 2
  • 7
  • 16

3 Answers3

1

What you need to do in your unittest to test http_exception return case is:

  1. patch cred_check.methodA to return False
  2. Instantiate a MyClass() object (you can also use a Mock instead)
  3. Call MyClass.methodB() where you can pass a MagicMock as request and check if the return value is an instance of http_exception

Your test become:

@mock.patch('cred_check.methodA', return_value=False, autospec=True)
def test_negative_cred(self, mock_A):
    obj = MyClass()
    #if obj is a Mock object use MyClass.methodB(obj, MagicMock()) instead
    response = obj.methodB(MagicMock()) 
    self.assertIsInstance(response, http_exception)
    #... and anything else you want to test on your response in that case
Michele d'Amico
  • 22,111
  • 8
  • 69
  • 76
1

To mock methods outside of a class:

  1. Add a @mock.patch("<your_module>.<your_method>")
  2. Within the test method parameter definition, add a parameter mock_<your_method>
  3. Within the test method, specify the return value as mock_<your_method> = <your_return_value>

Example: To test a method in a module at foo.py:

@mock.patch("foo.method_1")
@mock.patch("foo.method_2")
def test_example(self, mock_method_2, mock_method_1):
    mock_method_2.return_value = "test_value_2"
    mock_method_1.return_value = "test_value_1"
    
    result = example()
    
    self.assertTrue(result)

Notes:

  • When mocking methods, you're mocking the call and therefore if method_1 is in a different module called bar.py, you would still mock it with @mock.patch("foo.method_1")
  • If you want to mock multiple methods, the @mock.patch decorators are applied in nested order. Refer to the example to get clarification.
NKSM
  • 5,422
  • 4
  • 25
  • 38
  • `When mocking methods, you're mocking the call and therefore if method_1 is in a different module called bar.py, you would still mock it with @mock.patch("foo.method_1")` thats what did it for me, great tip! – ajbieber Aug 01 '23 at 17:15
0
 import unittest
 import mock
 import cred_check import MyClass

class TestMyClass(unittest.Testcase):
    @mock.patch('cred_check.methodA',return_value=False)
    @mock.patch.dict(req.retrieve,{'constants.USER':'user','constants.PW':'pw'})
    def test_negative_cred(self, mock_A,):
        obj=MyClass(#you need to send some object here)
        obj.methodB()

It should work this way.

vks
  • 67,027
  • 10
  • 91
  • 124
  • Thank you. I edited my original question to include what I was really trying to ask.. the username and password in methodB are requests methods. I guess those need to be patched too.. what would be the proper way of doing it? – James C. Mar 12 '15 at 21:40
  • @killahjc you can patch `request module's retrieve` too – vks Mar 13 '15 at 04:23
  • `@mock.patch.dict(req.retrieve,{'constants.USER':'user','constants.PW':'pw'})` have no sense. Maybe you need a mock instead patching an object that doesn't exist. – Michele d'Amico Mar 13 '15 at 08:38
  • @Micheled'Amico he wanted to mock `request` too...so i included that too...But he doesnt show how that object is coming – vks Mar 13 '15 at 08:41
  • Yes, but `req` cannot exist when the module was loaded so when patch is applied. Even if a reference exist maybe that is not the same object that you can get when test is running. Request can be a mock that you can create in your test: you don't need patch anything to get it because it is an `methodB` argument. – Michele d'Amico Mar 13 '15 at 09:12
  • @Micheled'Amico i guess it to be something like `import requests as req`.Ofcourse if its and object created somewhere else it wont work – vks Mar 13 '15 at 09:13