0

I'm using pytest to test a Flask API that also makes use of MQTT. I'm late to the TDD game so this question could well be answered elsewhere but I can't think of the right way to frame it, so can't find anything that seems to answer it for me. This question that deals with mocking during integration tests sounds like it's on the right track.

Basically one of my tests looks like this

response = testing_client.post(
         "/api/users/1/devices",
         data=json.dumps(dict(device)),
         headers={"Authorization": "Token %s" % auth_token},
         content_type="application/json",
     )
assert response.status_code == 200

The problem is that the corresponding bit of code that handles these POST requests also publishes an MQTT message when the request has been handled i.e.

publish.single(f"{device_id}/active", msg, hostname=os.environ.get("MQTT_BROKER_URL"), retain=True, qos=0, port=int(os.environ.get("MQTT_BROKER_PORT")))

The API and MQTT broker are separate containers managed using Docker compose. When I'm testing locally there is no MQTT broker running and so any test here fails (even though I don't actually care about testing the MQTT code).

For any calls to the DB (Postgres) I actually set up a specific postgres container for testing and run tests against this. Should I do the same thing for MQTT testing (I would then also have to do it during the CI pipeline on GitLab), or is there a much more obvious solution that I am missing?

Philip O'Brien
  • 4,146
  • 10
  • 46
  • 96

2 Answers2

0

You should definitely mock the test and create a mock return value. Imagine having 100 tests that perform a HTTP request, that becomes way too slow in your continuous integration progress (scales terribly).

Your code should handle both if the requests fails and if it's successful. For one case you mock the result as a success, and in the other as a failure. Then you test how your code would interact with the result.

monkeypatch.setattr("testing_client.post", lambda *args: some_return_value)
DKo
  • 820
  • 1
  • 9
  • 19
0

I tend to think mocking isn't very useful testing, because how do you know the mock is the same as the real thing? So another option for fast tests is a verified fake.

A verified fake is an object with same interface as real thing, and a set of tests validating that the fake and the real thing follow the same contract. https://pythonspeed.com/articles/verified-fakes/ has more details.

For integration tests using MQTT in another container may well be fine. The speed concern is quite often overdone—e.g. for databases (and maybe MQTT as well) you can usually make them run very fast in tests by disabling fsync. See https://pythonspeed.com/articles/faster-db-tests/

Itamar Turner-Trauring
  • 3,430
  • 1
  • 13
  • 17