Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Flask tests against a remote server

I'm writing "unittests" for my flask api. Using Flask.test_client() is easy locally. eg:

app = Flask(__name__)
client = app.test_client()

However, I want to still be able to do things such as

self.client.post('{0}/account/password'.format(self.base_path),
                              data=json.dumps(passwordu), headers=self.get_headers(),
                              content_type=self.content_type)

But I want the client to talk to a remote host.

I've seen I can use environ_override as a parameter to the client.post(...) method. To me there must be a simpler way to get a simple client that does the necessary sending of requests and decoding of responses in the same way test_client() does. However, subclassing client, still requires me to use a Flask instance.

like image 798
silverdagger Avatar asked Oct 28 '25 03:10

silverdagger


1 Answers

Ok, firstly, thanks for the suggestion Anarci. Here's what I came up with.

I wouldn't call it nice OO design, but it works and is lazy.

class RemoteApiTest(AppTest, ApiTestMixin):
    @classmethod
    def setUpClass(cls):
        super(RemoteApiTest, cls).setUpClass()
        cls.kwargs = config.FLASK_CLIENT_CONFIG
        cls.base_url = cls.kwargs.get('base_url')
        cls.content_type = cls.kwargs.get('content_type')
        cls.client = requests
        cls.db = db
        cls.db.create_all()

    @classmethod
    def tearDownClass(cls):
        super(RemoteApiTest, cls).tearDownClass()
        cls.db.session.remove()
        cls.db.drop_all()
        #cls.db.get_engine(cls.app).dispose()

    @property
    def base_url(self):
        return self.__class__.base_url

    @property
    def content_type(self):
        return self.__class__.content_type

    def get_json(self, r):
        return r.json()

    @property
    def headers(self):
        headers = {'content-type': self.content_type}
        if self.api_key:
            headers.update({'X-consumer-apiKey': self.api_key})
        return headers

    def basic_checks(self, rv):
        eq_(rv.status_code, 200)
        r = rv.json()
        assert rv is not None
        assert r is not None
        assert r.get('correlationID') is not None
        return r

    def setUp(self):
        super(RemoteApiTest, self).setUp()
        self.api_key = None

        r = self.client.post('{0}/account/register'.format(self.base_url), data=json.dumps(account_register),
                             headers=self.headers)
        j = r.json()
        self.api_key = j['apiKey']

    def tearDown(self):
        rv = self.client.delete('{0}/account'.format(self.base_url), headers=self.headers)
        super(RemoteApiTest, self).tearDown()

With that I can config the remote server etc in my same config, and I can reuse code like this:

class ApiTestMixin:
    def test_account_get(self):
        rv = self.client.get(self.base_url + '/account', headers=self.headers)
        r = self.basic_checks(rv)
        account = r.get('account')
        eq_(account.get('fullName'), account_register.get('fullName'))
        assert r.get('correlationID') is not None

Definitely open to criticism, but that's how I made it work,

like image 118
silverdagger Avatar answered Oct 30 '25 10:10

silverdagger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!