3
\$\begingroup\$
# unit tests for the /brands endpoint

from flask.ext import restful
import unittest
import os
import json
import sys

# tells sql_models to use the testing database
os.environ['API_TESTING'] = '1'
sys.path.append('/opt/backend_api/')

import api
from models import sql_models
from config import settings

class TestBrandsEndpoint(unittest.TestCase):

    def setUp(self):
        ''' fire up a test instance of the flask app '''
        self.app = api.APP.test_client()
        self.app.testing = True
        self.api = api.API
        self.test_brand_name = 'Momcorp'

    def tearDown(self):
        ''' 
            tear down app, reverse any changes made 
            - remove the brand inserted in test_post()
        '''
        brand_object = sql_models.Brand.get_by_name(self.test_brand_name)
        if brand_object is not None:
            sql_models.Brand.delete_brand(brand_object)
        pass

    def test_post(self):
        '''
            insert a new brand into the database
            - only given field for test is the mandatory brand name but could(should?) be extended for the rest
            - test that the response status code == 201 and the returned brand object has the correct name
        '''
        result = self.app.post( '/' + settings.BASE_API_VERSION + '/brands', 
                                headers=[('user-api-key', '<redacted>')],
                                data={'name':self.test_brand_name})
        # print(json.loads(result.data))
        self.assertEqual(result.status_code, 201)
        self.assertEqual(json.loads(result.data)['brand']['name'], self.test_brand_name)

    def test_get(self):
        ''' 
            get all brands and all currently running offers
            - sets the brand's 'offers_running' status
            - returns serialized brands like so: {'brands':[serialized_brands]}
            - test status code + name, id fields are not null
        '''
        result = self.app.get('/' + settings.BASE_API_VERSION + '/brands', headers=[('user-api-key','<redacted>')])
        self.assertEqual(result.status_code, 200)
        for brand in json.loads(result.data)['brands']:
            self.assertIsNotNone(brand['name'])
            self.assertIsNotNone(brand['id'])


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

Looking for advice about the 'right way' to do this. Not sure if I should have a separate file and class for each endpoint or if all endpoints+request types should just be their own methods in a larger TestAllEndpoints(unittest.TestCase) class. Any advice or opinions are appreciated.

\$\endgroup\$
  • \$\begingroup\$ Btw. I've edited the title to match the content more closely - if you can think of a better title that describes the purpose of the code better, please update it yourself. \$\endgroup\$ – ferada Aug 26 '16 at 12:08
3
\$\begingroup\$
  • Move the os.environ and sys.path calls into a new setUpClass method instead of have them at the global level?
  • pass at the end of setUp should be removed, similarly the commented out print.
  • I'd put the constants for the URL and the headers into fields or methods (self.url() / self.url) to reduce duplication.
  • The docstrings are a bit much. Ideally the code would be very self explanatory so that it almost spells out what you currently have (duplicated) in the docstring.
  • I'd put things that belong together in the same file; so same endpoint and requests definitely in the same file and probably in the same test class as well. I'd go for practicality first - if you need to have convoluted setup because you want to handle many different tests, then split it into multiple classes such that the tests are again easy to read.
\$\endgroup\$

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.