【问题标题】:Jest : Testing for type or null笑话:测试类型或空
【发布时间】:2018-12-10 12:23:00
【问题描述】:

我有一个测试,我想测试我收到的对象值类型是否与架构匹配。问题是对于某些键,我可能会收到一些东西或 null

目前为止我试过了

  const attendeeSchema = {
  birthDate: expect.extend(toBeTypeOrNull("Date")),
  contact: expect.extend(toBeTypeOrNull(String)),
  createdAt: expect.any(Date),
  firstName: expect.any(String),
  id: expect.any(Number),
  idDevice: expect.extend(toBeTypeOrNull(Number)),
  information: expect.extend(toBeTypeOrNull(String)),
  lastName: expect.any(String),
  macAddress: expect.extend(toBeTypeOrNull(String)),
  updatedAt: expect.any(Date),
  // state: toBeTypeOrNull()
};

    const toBeTypeOrNull = (received, argument) => {
  const pass = expect(received).toEqual(expect.any(argument));
  if (pass || received === null) {
    return {
      message: () => `Ok`,
      pass: true
    };
  } else {
    return {
      message: () => `expected ${received} to be ${argument} type or null`,
      pass: false
    };
  }
};

在我的测试中

 expect(res.result.data).toBe(attendeeSchema);

我也尝试过 tobeEqual 和其他东西......

我的测试没有通过

TypeError: any() expects to be passed a constructor function. Please pass one or use anything() to match any object.

我不知道在这里做什么.. 如果有人有想法 谢谢

【问题讨论】:

  • 您能否确定您的代码最初是哪一行触发了错误?你有很多电话给any 这里..
  • 我真的不知道导致错误的行没有给我一个精确的错误,但如果我只保留我的参加者模式的一行,我仍然有同样的错误。错误说我的架构文件的第 3 行是 const pass = expect(received).toEqual(expect.any(argument));

标签: javascript node.js jestjs


【解决方案1】:

其实我根本不知道 Jest,但我看了一下,因为我现在对代码测试很感兴趣。

从我在expect.extend documentation 中看到的情况来看,您似乎以错误的方式使用它。您当前将调用toBeTypeOrNull 的结果提供给它,例如在birthDate: expect.extend(toBeTypeOrNull("Date")), 中,而不是函数本身。这可能会导致调用有一个未定义的参数,因为它是用 2 个参数声明的 (received, argument)argument 然后未定义,您不能在自定义函数中执行 expect.any(argument)

根据我在文档中看到的,您应该在开头调用 extend 并使用包含所有自定义函数的对象,以便以后使用它们。试试这段代码,如果出现问题,请毫不犹豫地发表评论:

更新:objectContainingtoMatchObjectsee this answer之间的区别

expect.extend({
  toBeTypeOrNull(received, argument) {
    const pass = expect(received).toEqual(expect.any(argument));
    if (pass || received === null) {
      return {
        message: () => `Ok`,
        pass: true
      };
    } else {
      return {
        message: () => `expected ${received} to be ${argument} type or null`,
        pass: false
      };
    }
  }
});

//your code that starts the test and gets the data
  expect(res.result.data).toMatchObject({
    birthDate: expect.toBeTypeOrNull(Date),
    contact: expect.toBeTypeOrNull(String),
    createdAt: expect.any(Date),
    firstName: expect.any(String),
    id: expect.any(Number),
    idDevice: expect.toBeTypeOrNull(Number),
    information: expect.toBeTypeOrNull(String),
    lastName: expect.any(String),
    macAddress: expect.toBeTypeOrNull(String),
    updatedAt: expect.any(Date),
    // state: toBeTypeOrNull()
  });

【讨论】:

  • 感谢您为此所做的工作!我试过你的代码,但 toBeTypeOrNull 在我的测试中不是一个函数。这很奇怪,因为它在文档中是如何完成的
  • 再次查看文档后,我认为您可以尝试使用 objectContainingtoMatchObject 函数,因为您的 attendeeSchema 不是类型,而是对象,更新了答案,以便第二部分是测试本身而不是对象。
  • 它不工作。实际上,即使是开玩笑的文档也不起作用。我试过 expect({apples: 6, bananas: 3}).toEqual({ apples: expect.toBeDivisibleBy(2), bananas: expect.not.toBeDivisibleBy(2), });并且 toBeDivisibleBy(2) 不是一个函数。我不知道如何解决这个问题
  • 我会尝试在进行另一次更新之前直接对其进行测试,但现在不适合,因为我进入了一个忙碌的部分。如果你找到我感兴趣的东西;)
  • 好吧,我检查了文档,他们说这不应该是你应该测试的东西......所以这就是为什么他们没有添加任何东西来这样做。我放弃了,我现在要做的是测试我的对象是否包含我想要的密钥,无论是什么类型。
【解决方案2】:

我正在寻找可以验证任何类型或null 的东西,结果发现了这个答案,95% 正确。问题出在这条线上,因为预期无法尝试将 nullargument 进行比较。

const pass = expect(received).toEqual(expect.any(argument));

作为奖励,我创建了一个toBeObjectContainingOrNull。这是我的代码:

const expect = require("expect");

const okObject = {
    message: () => "Ok",
    pass: true
};

expect.extend({
    toBeTypeOrNull(received, argument) {
        if (received === null)
            return okObject;
        if (expect(received).toEqual(expect.any(argument))) {
            return okObject;
        } else {
            return {
                message: () => `expected ${received} to be ${argument} type or null`,
                pass: false
            };
        }
    },
    toBeObjectContainingOrNull(received, argument) {
        if (received === null)
            return okObject;

        const pass = expect(received).toEqual(expect.objectContaining(argument));
        if (pass) {
            return okObject;
        } else {
            return {
                message: () => `expected ${received} to be ${argument} type or null`,
                pass: false
            };
        }
    }
});

module.exports = { expect };

那么你可以使用toBeObjectContainingOrNull如下:

const userImageSchema = {
    displayName: expect.any(String),
    image: expect.toBeObjectContainingOrNull({
        type: "Buffer",
        data: expect.any(Array)
    }),
    orgs: expect.any(Array)
};

我希望它有所帮助。

【讨论】:

    【解决方案3】:

    之前给出的所有响应在其实现中都错误地使用了expect(),因此它们实际上并没有起作用。

    您想要的是一个类似于any() 但接受空值并且在其实现中不使用expect() 函数的笑话匹配器。您可以通过基本上复制原始的any() 实现(来自Jasmine)将其实现为扩展,但在开头添加了一个空测试:

    expect.extend({
      nullOrAny(received, expected) {
        if (received === null) {
          return {
            pass: true,
            message: () => `expected null or instance of ${this.utils.printExpected(expected) }, but received ${ this.utils.printReceived(received) }`
          };
        }
    
        if (expected == String) {
          return {
            pass: typeof received == 'string' || received instanceof String,
            message: () => `expected null or instance of ${this.utils.printExpected(expected) }, but received ${ this.utils.printReceived(received) }`
          };        
        }
    
        if (expected == Number) {
          return {
            pass: typeof received == 'number' || received instanceof Number,
            message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
          };
        }
    
        if (expected == Function) {
          return {
            pass: typeof received == 'function' || received instanceof Function,
            message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
          };
        }
    
        if (expected == Object) {
          return {
            pass: received !== null && typeof received == 'object',
            message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
          };
        }
    
        if (expected == Boolean) {
          return {
            pass: typeof received == 'boolean',
            message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
          };
        }
    
        /* jshint -W122 */
        /* global Symbol */
        if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
          return {
            pass: typeof received == 'symbol',
            message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
          };
        }
        /* jshint +W122 */
    
        return {
          pass: received instanceof expected,
          message: () => `expected null or instance of ${this.utils.printExpected(expected)}, but received ${this.utils.printReceived(received)}`
        };
      }
    });
    

    将上述内容放入.js 文件中,然后使用开玩笑的setupFilesAfterEnv 配置变量指向该文件。现在您可以像这样运行测试:

    const schema = {
      person: expect.nullOrAny(Person),
      age: expect.nullOrAny(Number)
    };
    
    expect(object).toEqual(schema);
    
    

    【讨论】:

    【解决方案4】:

    在前两个答案的基础上,更常见的方法是将核心匹配器包装在 try/catch 块中

    expect.extend({
      toBeTypeOrNull(received, classTypeOrNull) {
          try {
              expect(received).toEqual(expect.any(classTypeOrNull));
              return {
                  message: () => `Ok`,
                  pass: true
                };
          } catch (error) {
              return received === null 
                ? {
                      message: () => `Ok`,
                      pass: true
                  }
                : {
                      message: () => `expected ${received} to be ${classTypeOrNull} type or null`,
                      pass: false
                };
          }
      }
    });
    

    【讨论】:

    • IMO 这应该是公认的答案,因为expect.any(null) 会返回一个错误,需要被捕获,干得好
    【解决方案5】:

    我决定制作一个通用的“任何”,而不是制作特定的处理程序:

    expect.extend({
      toEqualAnyOf(received: any, argument: any[]) {
        const found = argument.some((eqItem) => {
          // undefined
          if (typeof eqItem === 'undefined' && typeof received === 'undefined') {
            return true;
          }
          // null
          if (eqItem === null && received === null) {
            return true;
          }
          // any expect.<any> or direct value
          try {
            expect(received).toEqual(eqItem);
            return true;
          } catch (e) {
            return false;
          }
        });
        return found
          ? {
              message: () => 'Ok',
              pass: true,
            }
          : {
              message: () => `expected ${received} to be any of ${argument}`,
              pass: false,
            };
      },
    });
    
    module.exports = { expect };
    

    而且可以这样使用:

    const userImageSchema = {
      displayName: expect.any(String),
      // null or undefined or part of structure or instance of a class
      image: expect.toEqualAnyOf([
        null,
        undefined,
        expect.objectContaining({
          type: 'Buffer',
          data: expect.any(Array),
        }),
        expect.any(ImageClass),
      ]),
      orgs: expect.any(Array),
    };
    

    【讨论】:

      猜你喜欢
      • 2018-02-04
      • 2018-08-09
      • 2019-09-06
      • 2019-08-17
      • 2021-06-13
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 2018-12-23
      相关资源
      最近更新 更多