简体   繁体   English

DRY Rest API 测试

[英]DRY Rest API testing

I'm making unit tests on my rest api with mocha and chai.我正在使用 mocha 和 chai 对我的 rest api 进行单元测试。 For the moment, for each request, (let's say a POST for example) I test the whole response body (excluding non static data like ids etc...).目前,对于每个请求(例如,假设一个 POST),我测试整个响应主体(不包括非静态数据,如 ids 等...)。 The problem is: if some day I decide to change the model of my resource, like maybe adding a new field.问题是:如果有一天我决定更改我的资源模型,比如添加一个新字段。 The actual tests won't check this new field.实际测试不会检查这个新字段。 So I'll have to update every test related to this resource, which can be complicated as the number of tests increases.所以我必须更新与此资源相关的每个测试,随着测试数量的增加,这可能会变得复杂。

So my question is: Am I doing it the right way?所以我的问题是:我这样做的方式正确吗? If not, what should I test in my api responses and what should I not?如果不是,我应该在我的 api 响应中测试什么,我不应该测试什么?

The DRY (Don't repeat yourself) principle applies to testing as well, but don't overdo it. DRY(不要重复自己)原则也适用于测试,但不要过度。 Tests should be "DAMP not DRY" .测试应该是“DAMP not DRY”

...if some day I decide to change the model of my resource, like maybe adding a new field. ...如果有一天我决定改变我的资源模型,比如添加一个新字段。 The actual tests won't check this new field.实际测试不会检查这个新字段。 So I'll have to update every test related to this resource...所以我必须更新与此资源相关的每个测试...

In this case what I usually do is create a Chai custom assertion that defines a set of assertions for a specific type, eg a Todo .在这种情况下,我通常做的是创建一个Chai 自定义断言,它为特定类型定义一组断言,例如Todo

This custom assertion is then (re)used in all relevant tests to verify that the returned object(s) actually pass the assertions for Todo , without having to repeat the same assertions in each and every test.然后在所有相关测试中(重新)使用此自定义断言,以验证返回的对象是否确实通过了Todo的断言,而不必在每个测试中重复相同的断言。

Here's an example:这是一个例子:

const chai = require('chai')
const chaiHttp = require('chai-http')
const server = 'https://jsonplaceholder.typicode.com'

chai.should()
chai.use(chaiHttp)
// Define a custom assertion for 'Todo'. We expect that a Todo always 
// has an `id` property of type `Number` and a `title` property of
// type `String`.
chai.use((chai, utils) => {
  utils.addProperty(chai.Assertion.prototype, 'Todo', function () {
    this._obj.should.have.property('id')
    this._obj.should.have.property('title')

    this._obj.id.should.be.a('Number')
    this._obj.title.should.be.a('String')
  })
})

// Begin Tests

describe('Retrieve a Todo', () => {
  it('returns a single Todo by ID', () => {
    return chai.request(server)
      .get('/todos/1')
      .then(res => {
        res.should.have.status(200)
        // Use the custom assertion to check if returned object
        // passes the assertions for `Todo`.
        res.body.should.be.a.Todo
      })
  })
})

describe('Retrieve all Todos', () => {
  it('returns a list containing 200 Todos', () => {
    return chai.request(server)
      .get('/todos')
      .then(res => {
        res.should.have.status(200)
        res.body.should.be.an('Array')
        res.body.should.have.length(200)
        // Reuse the custom assertion to check if all returned objects
        // pass the assertions for `Todo`.
        res.body.forEach(todo => todo.should.be.a.Todo)
      })
  })
})

If in the future I add a new field on Todo , ie completed , all I need to do is modify the custom assertion like so:如果将来我在Todo上添加一个新字段,即completed ,我需要做的就是像这样修改自定义断言:

chai.use((chai, utils) => {
  utils.addProperty(chai.Assertion.prototype, 'Todo', function () {
    this._obj.should.have.property('id')
    this._obj.should.have.property('title')
    this._obj.should.have.property('completed')

    this._obj.id.should.be.a('Number')
    this._obj.title.should.be.a('String')
    this._obj.completed.should.be.a('Boolean')
  })
})

... what should I test in my api responses and what should I not? ...我应该在我的 api 响应中测试什么,我不应该测试什么?

As a minimum I would check if:至少我会检查是否:

  • The response HTTP status is correct.响应HTTP 状态正确。
  • The response body has the appropriate properties and correct types for each property.响应主体具有适当的属性和每个属性的正确类型。
  • If the response is a list of items, I would check if the response body is indeed an Array , if it has the length I expect it to have and if each element in the Array has the correct properties and types.如果响应是一个项目列表,我会检查响应主体是否确实是一个Array ,它是否具有我期望的length以及Array中的每个元素是否具有正确的属性和类型。

There's no "rules" here.这里没有“规则”。 At the end it's a risk/time decision.最后,这是一个风险/时间决定。 Maintaining a test suite takes time.维护测试套件需要时间。 If I'm building a simple todo app for my own use, I won't concern myself too much with exhaustive testing.如果我正在构建一个简单的待办事项应用程序供自己使用,我不会太担心详尽的测试。 However if I'm building a public payment server, I'd definitely want my tests to be as exhaustive as possible.但是,如果我正在构建一个公共支付服务器,我肯定希望我的测试尽可能详尽。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM