Writing unit tests for a REST-ful API

2020-05-23 18:50发布

问题:

I'm planning on writing unit tests for a REST-ful API and I'm wondering about the approach I should take.

The aspect that concerns me the most is related to the database state. My understanding is that the environment, or the initial state, of a test target should be the same for each test, which means that the database should also be the same for each test. How do I achieve that when I have a heavy database? Also, how do I handle eventual changes in the database schema?

回答1:

Question is what do you want to test. What do you think will break at the topmost api-layer (i.e. layer which is receiving HTTP request)?

Generally writing a unit-test restful-api sounds a bit like an oxymoron ;) By definition unit-tests are much smaller as using entry-point HTTP to database. It sounds more that your question is based on how to write large-tests (or acceptance, end-to-end test).

Beware that implementing such large-tests (end-to-end test) involves high effort:

  • Tests tend to be much slower
  • Maintenance costs of tests, because tests are tougher to comprehend (because of all this dependecies + test-data setups)
  • they are more prone to cause false-positive tests (test shows 'red' though it should be 'green'). Reason again is that more dependencies are involved in your tests, fragility is more likely.

In my experience diversity of test-granularity is king, therefore I mix/combine approaches:

  • unit-testing for api-internals (e.g. several more complex mapping requirements, authentication, tricky validation rules, complicated if/else logic, ...)
  • doing smoke-tests on more coarse grained level, HTTP client is talking to api, i.e. testing integration. These tests would show me: server could start-up, main api use-cases works. As tool I recommend soap-ui.
  • regarding database-state: I often start with most basic data (e.g. existing api-users or predefined immutable test-data). Test-data for each test should be isolated. If my test includes more complicated flow (e.g. a whole use-case is spread over multiple HTTP calls), test-data is allowed to depend on test-steps (i.e. call-2 might depend on server-state which got changed by call-1)

Maybe you can give more input on a specific use-case you want to test, so can give more help?



回答2:

Usually, in unit tests, you try to remove all dependencies beyond the unit (usually a function/class/object) that you are testing. The classic way to accomplish this in your case (for databases) is through the use of mocks. http://en.wikipedia.org/wiki/Mock_object

Basically, you implement a "FakeDatabase" that shares the API of the actual database that returns known values.