【问题标题】:NestJs - How to unit test a DTO?NestJs - 如何对 DTO 进行单元测试?
【发布时间】:2020-07-06 04:41:15
【问题描述】:

我在向你寻求帮助。我创建了一个看起来像它的 DTO(这是一个较小的版本):

export class OfImportDto {

    @IsString({
        message: "should be a valid product code"
    })
    productCode: string;

    @IsString({
        message: "Enter the proper product description"
    })
    productDescription: string;

    @IsDateString({
        message: "should be a valid date format, for example : 2017-06-07T14:34:08+04:00"
    })
    manufacturingDate : Date

    @IsInt({
        message: "should be a valid planned quantity number"
    })
    @IsPositive()
    plannedQuantity: number;

问题是我要求使用单元测试而不是 E2E 测试来测试它。我不知道该怎么做。例如,我想进行单元测试 1/如果我的产品代码是一个字符串,应该创建一个字符串,如果不是,抛出我的异常 2/如果我的产品描述是一个字符串,应该创建一个字符串,如果不是,抛出我的异常 ... 等等。

那么,我可以制作一个 spec.ts 文件来测试它吗?如果是,如何? 如果不是,最好在 service.spec.ts 中测试它吗?如果有,怎么做?

非常感谢,任何帮助都会非常有帮助:)

【问题讨论】:

    标签: javascript node.js nestjs


    【解决方案1】:

    您应该为 DTO 的单元测试创​​建一个单独的 DTO 特定文件,例如 of-import.dto.spec.ts。让我们一步一步来看看如何在 Nest.js 中测试一个 DTO。


    TLDR:您的 DTO 的单元测试

    要逐行理解,请继续阅读:

    it('should throw when the planned quantity is a negative number.', async () => {
      const importInfo = { productCode: 4567, plannedQuanity: -10 }
      const ofImportDto = plainToInstance(OfImportDto, importInfo)
      const errors = await validate(ofImportDto)
      expect(errors.length).not.toBe(0)
      expect(stringified(errors)).toContain(`Planned Quantity must be a positive number.`)
    }
    

    创建一个普通对象进行测试

    以下是您要测试验证的对象:

    const importInfo = { productCode: 4567, plannedQuanity: -10 }
    

    如果您的测试对象有嵌套对象或太大,您可以跳过那些复杂的属性。我们将看看如何处理。


    将测试对象转换为DTO的类型

    使用class-transformer 包中的plainToinstace() 函数:

    const ofImportDto = plainToInstance(OfImportDto, importInfo)
    

    这会将您的普通测试对象转换为您的 DTO 类型的对象,即OfImportDto

    如果您在 DTO 中有任何转换,例如修剪属性值的空格,它们将在此时应用。如果您只是想测试转换,您现在可以断言,您不必调用以下validate() 函数来测试转换。


    模拟验证

    使用class-validator 包中的validate() 函数:

    const errors = await validate(ofImportDto)
    

    如果你在创建测试对象时跳过了一些属性,你可以像下面这样处理:

    const errors = await validate(ofImportDto, { skipMissingProperties: true })
    

    现在验证将忽略缺失的属性。


    断言错误

    断言errors 数组不为空并且包含您的自定义错误消息:

    expect(errors.length).not.toBe(0)
    expect(stringified(errors)).toContain(`Planned Quantity must be a positive number.`)
    

    这里的stringified()是一个帮助函数将errors对象转换为JSON字符串,所以我们可以搜索它是否包含我们自定义的错误信息:

    export function stringified(errors: ValidationError[]): string {
      return JSON.stringify(errors)
    }
    

    就是这样!希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      可以创建一个OfImportDTO.spec.ts 文件(或任何您的原始文件),但问题是,这里没有任何逻辑可以测试。您可以做的最接近的事情是从class-validator 创建Validator 的实例,然后实例化OfImportDto 的实例,然后检查该类是否通过验证。如果您向其添加逻辑(例如具有特定功能的 getter 和 setter),那么它可能对单元测试有意义,但除此之外,这基本上是一个被称为类的接口,因此它在运行时存在 class-validator

      【讨论】:

      • 是的,我也是这么想的。是否可以通过我的 service.spec.ts 对其进行测试?因为里面有逻辑,也许调用 DTO 的 mock 并做一些测试会起作用?
      • 什么样的逻辑,因为在您的代码 sn-p 上面它只是字段的定义以及装饰器。你想用这个测试什么?
      • 我仍然看不到任何关于 DTO 文件的测试。测试服务和控制器是另一回事,但在这种情况下测试 DTO 文件没有多大意义
      • 我想要的是确保来自 dto 的数据是好的。我想知道我是否可以检查服务测试中的每个字段。例如:如果产品代码不是字符串,则拒绝它。基于 dto 而不是实体。有可能吗?
      • 就像我在回答中所说的那样,您始终可以使用来自class-validatorValidator 的实例,以确保您的装饰器提供您期望的强制执行。这就是为什么 Nest 有 pipe 增强器:用于数据验证和转换。但除此之外,针对 DTO 文件运行自动化测试并没有真正的用处。
      猜你喜欢
      • 1970-01-01
      • 2012-01-08
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      • 2020-08-13
      • 2020-08-27
      • 2020-05-15
      • 2020-05-03
      相关资源
      最近更新 更多