14

I have noticed during integration testing that I actually work on recurring use cases with restful APIs (or in general HTTP interfaces) I check here and there with bash+cURL.

It starts looking quite messy and gets harder to maintain. Why deliver mess?

Typical use cases are:

  • Check that an URL returns http response code e.g. 200
  • Check that content type matches some MIME you need in that case
  • Check that returned content matches some pattern, or passes an abstract validation procedure

What I have found so far and consider a workable option without reinventing the wheel, is:

  • have a go with PyCurl - in a hope it fully implements all cURL options esp. proxying but also other switches I might need
  • use Python's built in unit testng

Then I could have, for example, one unit test per service I'd like to check:

import unittest, pycurl

class TestService (unittest.TestCase):

    def test_1(self):
        self.assertEqual(pycurl.returncode("some_url"), 200)

    def test_2(self):
        self.assertTrue(pycurl.response("some_url").matches ("xxx") )

    def test_3(self):
        self.assertTrue (pycurl.ContentType("some_url").equal("xxx"))

if __name__ == '__main__':
    unittest.main()

Does this make sense or is there a more high-level (but not too complex to pick up and integrate) tooling?

  • 1
    What is the API code ? there's a bunch of integration test systems and choosing one is usually done on the same language as the code being tested so the same dev can update both. – Tensibai Nov 16 '17 at 14:09
  • this can be heterogeneuos and I have no control – Peter Nov 16 '17 at 14:14
  • 1
    So what is the language your team is the more comfortable with ? Every tool will do to test this kind of things, from bash+curl to capistrano post deploy hooks... – Tensibai Nov 16 '17 at 14:16
  • 2
    In chef ecosystem you'll find inspec which can answer your question with the http resource, but it's based on serverspec/rspec, so it's more a ruby world than python world but may worth the try. – Tensibai Nov 16 '17 at 14:19
  • 2
    I've been working on some python code to do REST calls using Python's requests library. It will let you add any header you want and supports HTTP(s) proxy support, so it should be capable of supporting all of curl's features. You are welcome to borrow my code for your needs or use it as an example if it is helpful. – James Shewey Nov 16 '17 at 16:42
7

You could look at tools such as Postman which focuses on testing REST APIs with JavaScript - it has some nice features but you lose the use of Python.

Instead, I'd suggest looking at REST-related plugins for pytest, a Python test framework that simplifies your test code, while still running tests written using unittest.

Pytest has a huge set of plugins that simplify various tasks, including:

  • Tavern, which specialises in testing REST APIs and seems highly relevant here - sort of "Postman for Python unit tests".

  • pytest-curl-report - when testing with the requests library, will print a curl command you can use to reproduce the error from shell.

  • Testinfra - focuses on server testing (e.g. state of OS packages, files, processes, etc, usually tested on remote servers) - strongly recommended if you also need this type e.g. to test Ansible code.

    • For those who use Puppet or Chef, Testinfra is similar to Beaker (with RSpec), ServerSpec or InSpec.

If you don't like Tavern, you can of course use pycurl with pytest, which makes it easier to diagnose exactly what failed. This example from the pytest-curl-report site uses only generic pytest features:

$ py.test test.py
============================= test session starts ==============================
platform darwin -- Python 2.7.9 -- py-1.4.27 -- pytest-2.6.4
plugins: curl-report, httpbin, cache, capturelog, cov, flakes, pep8
collected 1 items

test.py F

=================================== FAILURES ===================================
______________________________ test_requests_get _______________________________

    def test_requests_get():
        r = requests.get('http://httpbin.org/get')
>       assert False
E       assert False

test.py:7: AssertionError

Pytest lets you write all tests with a plain assert, and optionally include a helpful message as part of the output. For example, one of your tests could be written:

def test_2():
    assert pycurl.response("some_url").matches ("xxx"), "xxx not found in response"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.