You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Chai中深度比较对象时校验指定属性的类型

Chai深度断言API响应时处理未知属性的方案

假设我们调用Restful Booker API的GET预订接口,得到如下响应:

{
    "bookingid": 4693,
    "booking": {
        "firstname": "firstname",
        "lastname": "lastname",
        "totalprice": 9999,
        "depositpaid": false,
        "bookingdates": {
            "checkin": "2018-01-01",
            "checkout": "2019-01-01"
        },
        "additionalneeds": "additional needs"
    }
}

我希望用Chai的深度断言直接对比完整对象,避免逐属性断言,理想的断言结构类似:

expect(response.data).to.deep.equal({
    bookingid: ?, // 这里的值未知,需要断言它是数字/整数
    booking: {
        firstname: 'firstname',
        lastname: 'lastname',
        totalprice: 9999,
        depositpaid: false,
        bookingdates: {
            checkin: '2018-01-01',
            checkout: '2019-01-01'
        },
        additionalneeds: 'additional needs'
    }
});

现在有两个问题:

  1. 能否在保持这种整体结构的前提下,仅断言bookingid为数字/整数?
  2. 这种方法是否常用,有没有不推荐的理由?

实现方法

当然可以实现,以下几种思路能兼顾整体结构和未知属性的类型验证:

方法1:拆分断言但保持逻辑关联

先单独验证bookingid的类型,再用深度断言匹配已知的booking对象,既保留整体结构的验证,又处理了未知属性:

// 验证bookingid是整数
expect(response.data.bookingid).to.be.an('integer');
// 深度匹配已知的booking对象结构
expect(response.data.booking).to.deep.equal({
    firstname: 'firstname',
    lastname: 'lastname',
    totalprice: 9999,
    depositpaid: false,
    bookingdates: {
        checkin: '2018-01-01',
        checkout: '2019-01-01'
    },
    additionalneeds: 'additional needs'
});
// 可选:验证响应仅包含这两个属性
expect(response.data).to.have.all.keys('bookingid', 'booking');

方法2:用satisfy包裹整体断言

如果想把所有断言逻辑放在一个代码块里,可使用Chai的satisfy方法,在回调中完成类型验证和深度匹配:

expect(response.data).to.satisfy(data => {
    // 验证bookingid是整数
    expect(data.bookingid).to.be.an('integer');
    // 验证booking对象完全匹配
    expect(data.booking).to.deep.equal({
        firstname: 'firstname',
        lastname: 'lastname',
        totalprice: 9999,
        depositpaid: false,
        bookingdates: {
            checkin: '2018-01-01',
            checkout: '2019-01-01'
        },
        additionalneeds: 'additional needs'
    });
    // 必须返回true表示满足断言条件
    return true;
});

方法3:结合deep.include和类型断言

如果API可能返回不影响业务的额外属性,用deep.include匹配已知部分,同时单独验证bookingid:

expect(response.data).to.deep.include({
    booking: {
        firstname: 'firstname',
        lastname: 'lastname',
        totalprice: 9999,
        depositpaid: false,
        bookingdates: {
            checkin: '2018-01-01',
            checkout: '2019-01-01'
        },
        additionalneeds: 'additional needs'
    }
});
expect(response.data.bookingid).to.be.an('integer');

方法的实用性与注意事项

  • 是否常用? 这种混合类型验证和深度匹配的方法在接口测试中很常见,尤其适用于大部分属性固定、少数属性为动态生成(如ID、时间戳)的场景,能有效减少断言代码冗余。
  • 不推荐的场景:
    • 当接口返回的对象结构极复杂、嵌套层级过深时,这种断言会变得难以维护,不如逐关键属性断言清晰。
    • 若使用deep.equal做完全匹配,一旦API新增非预期属性,断言会直接失败——如果这些新增属性不影响业务,反而会导致测试用例误报,这种场景下用deep.include更稳妥。
    • 若bookingid有更严格的规则(如范围、非负数),仅验证类型会遗漏边界条件,需要补充对应断言。

内容的提问来源于stack exchange,提问作者Hans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:46:04