Search code examples
pythonflaskflask-testing

How to test python/flask app with third-party http lib?


I have a purest suite for my flask app that works great. However, I want to test some of my code that uses a third-party library (Qt) to send http requests. How is this possible? I see flask-testing has the live_server fixture which accomplishes this along with flask.url_for(), but it takes too much time to start up the server in the fixture.

Is there a faster way to send an http request from a third-party http lib to a flask app?

Thanks!


Solution

  • Turns out you can do this by manually converting the third-party request to the FlaskClient request, using a monkeypatch for whatever "send" method the third-party lib uses, then convert the flask.Response response back to a third-party reply object. All this occurs without using a TCP port.

    Here is the fixture I wrote to bridge Qt http requests to the flask app:

    @pytest.fixture
    def qnam(qApp, client, monkeypatch):
    
        def sendCustomRequest(request, verb, data):
            # Qt -> Flask
            headers = []
            for name in request.rawHeaderList():
                key = bytes(name).decode('utf-8')
                value = bytes(request.rawHeader(name)).decode('utf-8')
                headers.append((key, value))
            query_string = None
            if request.url().hasQuery():
                query_string = request.url().query()
            # method = request.attribute(QNetworkRequest.CustomVerbAttribute).decode('utf-8')
            # send
            response = FlaskClient.open(client,
                                        request.url().path(),
                                        method=verb.decode('utf-8'),
                                        headers=headers,
                                        data=data)
            # Flask -> Qt
            class NetworkReply(QNetworkReply):
                def abort(self):
                    pass
            reply = NetworkReply()
            reply.setAttribute(QNetworkRequest.HttpStatusCodeAttribute, response.status_code)
            for key, value in response.headers:
                reply.setRawHeader(key.encode('utf-8'), value.encode('utf-8'))
            reply.open(QIODevice.ReadWrite)
            reply.write(response.data)
            QTimer.singleShot(10, reply.finished.emit) # after return
            return reply
    
        qnam = QNetworkAccessManager.instance() # or wherever you get your instance
    
        monkeypatch.setattr(qnam, 'sendCustomRequest', sendCustomRequest)
        return ret