TypeScript中用于断言类上每个属性的通用测试具有指定的值

时间:2017-08-26 12:21:05

标签: unit-testing typescript reflection jest

我有一个TypeScript +2.4项目,我使用Jest进行单元测试。该项目有很多poco模型,没有默认值。例如:

export class Foo {
    public id: number
    public name: string;
    public when: Date;
}

这些模型中的每一个都从原始json映射到此类。我的测试要求所有属性都被分配,例如有价值。这导致必须为所有模型编写以下测试:

test('Foo() should have its properties assigned', () => {
    const target: Foo = {
        id: 1001, name: 'whatever', when: new Date()
    };

    // manually assert each propertie here
    expect(target.id).toBeDefined();
    expect(target.name).toBeDefined();
    expect(target.when).toBeDefined();
}

对我来说,每次测试都不是那么干。更不用说容易出错和繁琐了。我想要做的是创建一个帮助程序,遍历每个属性并断言它已赋值。

示例1 - Object.keys
此示例不正确,因为Object.keys仅遍历已分配的属性,忽略非设置属性(因此始终为正):

public static AssertAllPropertiesAreAssigned(target: object): void {
    Object.keys(target).forEach((key, index) => {
        expect(target[key]).toBeDefined();
});

示例2 - Object.getOwnPropertyNames()
与例1相同:

public static AssertAllPropertiesAreAssigned(target: object): void {
    Object.getOwnPropertyNames(target).forEach((name, index) => {
        expect(target[name]).toBeDefined();
});

示例3 - 设置默认值
通过为每个poco分配默认值,例如null,我可以使早期的样本有效。但我确实想不惜一切代价避免这种情况:

export class Foo {
    public id: number = null;
    public name: string = null;
    public when: Date = null;
}

问题:有没有办法在我的测试中创建一个帮助器,断言我的TypeScript poco对象的每个属性实际上都赋值了?或者,作为替代方案,Jest是否有一些实用工具?

在SO上有类似的问题,但它们与在测试中断言值无关。这使得这个问题,就我所环顾的而言,与其他问题不同:

另外,我知道我的poco的Javascript编译输出可能会导致未设置的属性根本不可用:

var Foo = (function() {
    // nothing here...
}());

但是凭借TypeScript强大的打字能力以及最近的更改和/或Jest助手,可能还有其他一些选项可以完成这项工作?

1 个答案:

答案 0 :(得分:1)

您的大多数选择都没有比其他问题的答案更好:初始化属性(好主意);使用属性装饰器(繁琐)。

就我个人而言,我认为将类属性声明为像string这样的不可定义类型然后在构造函数中没有定义它应该是错误的,但是feature isn't part of TypeScript ,即使你打开strictNullChecks(你应该)。我不知道为什么你不想初始化变量,但这可行:

export class Foo {
    public id: number | undefined = void 0;
    public name: string | undefined = void 0;
    public when: Date | undefined = void 0;
}

现在Foo的实例如果您执行Object.keys(),则会有相关的密钥,即使这些值仍为undefined

等一下,你甚至没有在运行时使用该类:

const target: Foo = { 
    id: 1001, name: 'whatever', when: new Date()
}; // object literal, not constructed class instance
console.log(target instanceof Foo) // false

然后我建议您使用interface代替class,然后启用strictNullChecks

export interface Foo {
    id: number;
    name: string;
    when: Date;
}

const target: Foo = {
    id: 1001, name: 'whatever', when: new Date()
};
const badTarget: Foo = {
    id: 1002; 
}; // error, Property 'name' is missing

现在,TypeScript不允许您为这些属性分配可能未定义的值,并且您不必在运行时对任何内容进行循环。

希望有所帮助!