Unit testing an API wrapper - python

I'm writing a Python wrapper for an authenticated RESTful API. I'm writing up my test suite right now (Also first time test-writer here) but have a few questions:
1.a) How can I make a call, but not have to hardcode credentials into the tests since I'll be throwing it on Github?
1.b) I kind of know about mocking, but have no idea how to go about it. Would this allow me to not have to call the actual service? What would be the best way to go about this?
2) What do I test for - Just ensure that my methods are passing certains items in the dictionary?
3) Any best practices I should be following here?

Hey TJ if you can show me an example of one function that you are writing (code under test, not the test code) then I can give you an example test.
Generally though:
1.a You would mock the call to the external api, you are not trying to test whether their authentication mechanism, or your internet connection is working. You are just trying to test that you are calling their api with the correct signature.
1.b Mocking in Python is relatively straight forward. I generally use the mocking library written by Michael Foord. pip install mock will get you started. Then you can do things like
import unittest
from mock import call, patch
from my_module import wrapper_func
class ExternalApiTest(unittest.TestCase):
#patch('my_module.api_func')
def test_external_api_call(self, mocked_api_func):
response = wrapper_func('user', 'pass')
self.assertTrue(mocked_api_func.called)
self.assertEqual(
mocked_api_func.call_args_list,
[call('user', 'pass')]
)
self.assertEqual(mocked_api_func.return_value, response)
In this example we are replacing the api_func inside my_module with a mock object. The mock object records what has been done to it. It's important to remember where to patch. You don't patch the location you imported the object from. You patch it in the location that you will be using it.
You test that your code is doing the correct thing with a given input. Testing pure functions (pure in the functional programming sense) is pretty simple. You assert that given a input a, this function returns output b. It gets a bit trickier when your functions have lots of side effects.
If you are finding it too hard or complicated to test a certain functiob/method it can mean that it's a badly written piece of code. Try breaking it up into testable chunks and rather than passing objects into functions try to pass primitives where possible.

Related

Testing practice an API wrapper without using unittest module

i have wrote an api wrapper which has around 70 endpoints. To test them all
https://paste.ubuntu.com/p/V6mkK4dSdh/
i have wrote this script without actually usign the unit testing module. Is it a good practice and what are the downsides when compared with unit testing? Really could use some comments.
This is not "testing". This is just checking that "they work".
However, in this context, "work" just means that they don't raise exceptions. That's a requirement, but not even close to "testing". The fact that you endpoint return some result does not mean that the result is correct.
Really testing would mean: When I call f(1, 2) I expect to get 5 as a response. So, you would need multiple tests, manually written, for each endpoint. Of course, that takes time...

(Monkey) patch for micro python unit test

I can’t find any examples, I will try to make the question specific:
Given that micropython has some form of unit test library, how can I do monkey patch or similar to replace system objects output or input within test cases.
The desire is to write test cases that cannot be mocked without altering the actual implementation code just for test, I.e network or file system objects replaced with mocks using patch - or a similar manual way of overriding the system objects for test purposes.
You can try the technique I laid out in https://forum.micropython.org/viewtopic.php?t=4475#p25925
# load in the module for patching (make sure this gets run before other imports)
import modulename
# create a modified version of modulename, cherry-picking from the real thing
patchedmodule = ...
# replace the module with your modified one for all future imports
sys.modules['modulename']=patchedmodule

Testing Python code that relies on hardware

So I have some code which uses gphoto2 to capture some images and stuff, I figured the best way to test this would be to wrap the gphoto2 code in something like an if TESTING: then return fake data, else do the gphoto2 stuff.
Does anyone know how I would achieve this, I've tried googling some things but I've not had any luck with specifically detecting if unit tests are being run or not.
I'd assume it would be something like if unittest: but maybe there is a better way to do this altogether?
EDIT:
So based on the comments and answers so far, I tried out the unittest.mock package, it didn't work as I'd hoped, let me explain.
If I have method A which calls the capture image method (method B), then saves the image and a few other bits. I've managed to mock method B so that it returns either the image or None, which works fine when I call method B specifically, but when I try to call method A, it doesn't use the mock of method B, it uses the actual method B.
How do I make method A use the mock method B?
The mock package exists for this very reason.
It's a standalone, pip-installable package for Python 2; it has been incorporated into the standard library for Python versions >= 3.3 (as unittest.mock).
Just use a mocking library from within your test code. This way you'd mask the external APIs (hardware calls in your case) and return predictable values.
I would recommend flexmock https://pypi.python.org/pypi/flexmock it's super easy.
In the beginning of your test code, you'll write something like:
flexmock(SomeObject).should_receive('some_method').and_return('some', 'values')

Isn't using `urllib2.install_opener` dangerous?

I am working on a project where it would be very handy if I could mock out urlopen during testing. Someone pointed out to me that this is possible (and easy) by mocking out an opener and using urllib2.install_opener.
However, I'm concerned because of this note in the documentation:
Install an OpenerDirector instance as the default global opener.
Doesn't this mean that my program could unexpectedly break if other code that I rely on is using urlopen?
The implications are exactly what you'd expect. All subsequent calls to urllib2.urlopen in your program, until your either exit or call install_opener again, will use your opener.
Whether that's "dangerous" depends on your use case. If there are other parts of your code that are using urllib2.open and you don't want them mocked, then yes, this is a bad idea, because they will be mocked.
In that case, you'll have to get the to-be-mocked code to call my_opener.open instead of urllib2.open. If you design your code to be tested, this should be easy. If you need to monkeypatch code after the fact, it's a little trickier, but there are all kinds of possibilities. For example, if you want to mock all calls in a given module, just replace foomodule.urllib2 = my_opener and set my_opener.urlopen = my_opener.open.

Using mock objects without tying down unit tests

I'm currently writing a set of unit tests for a Python microblogging library, and following advice received here have begun to use mock objects to return data as if from the service (identi.ca in this case).
However, surely by mocking httplib2 - the module I am using to request data - I am tying the unit tests to a specific implementation of my library, and removing the ability for them to function after refactoring (which is obviously one primary benefit of unit testing in the firt place).
Is there a best of both worlds scenario? The only one I can think of is to set up a microblogging server to use only for testing, but this would clearly be a large amount of work.
You are right that if you refactor your library to use something other than httplib2, then your unit tests will break. That isn't such a horrible dependency, since when that time comes it will be a simple matter to change your tests to mock out the new library.
If you want to avoid that, then write a very minimal wrapper around httplib2, and your tests can mock that. Then if you ever shift away from httplib2, you only have to change your wrapper. But notice the number of lines you have to change is the same either way, all that changes is whether they are in "test code" or "non-test code".
Not sure what your problem is. The mock class is part of the tests, conceptually at least. It is ok for the tests to depend on particular behaviour of the mock objects that they inject into the code being tested. Of course the injection itself should be shared across unit tests, so that it is easy to change the mockup implementation.

Categories

Resources