【问题标题】:Execute code after Jasmine test failureJasmine 测试失败后执行代码
【发布时间】:2017-02-09 21:53:50
【问题描述】:

只有在 Jasmine 测试失败时才可以做某事吗?与afterEach() 并列,无论结果如何,它都会在it() 之后执行,我正在寻找某种方法来仅在it() 预期失败后执行代码。

这个问题不是 Angular 特定的,但在我的场景中,我正在测试一个使用 $log 输出调试消息的 Angular 服务。我不想让我的控制台因测试成功而变得混乱,而只想显示失败测试的附加信息。

describe("MyService", function() {
    var MyService, $log;

    beforeEach(function() {
        inject(function (_MyService_, _$log_) {
            MyService = _MyService_;
            $log = _$log_;
        });
    });

    afterEach(function () {
        if (/* test failed */) {
            //console.log($log.debug.logs);
        }
    });

    it("should output debug logs when this fails", function() {
        //do something with MyService that would put a message in $log
        expect(false).toBe(true);
    });
});

我正在运行 Jasmine 2.2.0。

编辑:here 是一个非常简单的小提琴,它显示 Jasmine 1.3 jasmine.getEnv().currentSpec 解决方案不再有效。

【问题讨论】:

    标签: logging jasmine


    【解决方案1】:

    这是在 Jasmine 2 中重新启用 jasmine.getEnv().currentSpec 的技巧(有点,result 不是完整的 spec 对象,但包含 iddescriptionfullNamefailedExpectations , 和passedExpectations):

    jasmine.getEnv().addReporter({
        specStarted(result) {
            jasmine.getEnv().currentSpec = result;
        },
        specDone() {
            jasmine.getEnv().currentSpec = null;
        }
    });
    

    【讨论】:

    • 不错!我从没想过(ab)使用 Jasmine 的记者来替换这一点功能,而且对我来说这似乎一点也不 hacky。 Here's 一个更新的小提琴显示它用于代替旧的 jasmine.getEnv().currentSpec,它确实允许您在完成后立即检查规范的结果。
    • 我接受这是最佳答案,因为它是一个干净的解决方案,提供了我正在寻找的功能。
    • 出色的解决方案。哇 :D @tlrobinson 谢谢 :)
    • 请注意,如果您在项目中使用 TypeScript,它将声称 currentSpec 没有属性 failedExpectations。但是,如果您在运行时检查 currentSpec,您会看到它确实包含该属性和此答案中的其他属性。解决此问题的最简单方法是强制转换为 any 类型。 specStarted(result: any)addReporter 代码中,const currentSpec: any = jasmine.getEnv().currentSpec 在您的规范代码中。
    【解决方案2】:

    我终于想出了如何使用 Jasmine 2.3.4 获取对失败规范结果的引用,但我不确定它是否正是您正在寻找的。​​p>

    我使用了随 Jasmine 设置一起安装的 vanilla PlayerSpec.js 文件。我运行 SpecRunner.html 文件来执行测试。

    这是我在 PlayerSpec 文件中所做的更改:

    describe("Player", function() {
      var player;
      var song;
      var index = 0;
    
      beforeEach(function() {
        player = new Player();
        song = new Song();
        this.index = index++;
      });
    
      afterEach(function() {
        if (this.index > 0)
        {   var failed = jsApiReporter.specResults(this.index -1, 1)[0].failedExpectations;
            console.log('failed: ', failed);
            if (failed.length > 0)
            {
                console.log('After: ', this, failed[0].message);
                alert('ha');
            }
        }
      });
      it("should not fail", function()
      { expect(1).toEqual(2);
      });
    ...
    

    文件的其余部分与原来相同。

    这是我改变的:

    添加了一个索引变量来跟踪当前的规格编号。

    在 beforeEach 函数中,我将索引值添加到在 it、beforeEach 和 afterEach 函数之间传递的“this”对象。这使我可以根据需要在它们之间进行通信。我只是使用这种机制来传递索引。谨防!如果你只是尝试使用索引值,它是行不通的!这些函数是异步处理的,因此索引值很可能不是您在 afterEach 函数中所期望的值。

    在 afterEach 函数中,我检查以确保索引大于 0。在我的本地测试中,第一个规范失败,但直到第二次调用 afterEach 时才被识别。这是我不确定这是否会如您所愿的原因之一。然后,我获取对 failedExpectations 的引用,并在发现错误时进行一些条件处理。

    存在的最后一个更改是添加会导致失败的新规范。

    这是我的 FireBug 控制台结果的糟糕副本:

    failed: [Object { matcherName="toEqual",  message="Expected 1 to equal 2.",  stack="stack@http://localhost:4...ne-2.3.4/boot.js:110:5\n",  more...}]
    PlayerSpec.js (line 15)
    After: Object { index=1} Expected 1 to equal 2.
    PlayerSpec.js (line 18)
    failed: []
    PlayerSpec.js (line 15)
    failed: []
    PlayerSpec.js (line 15)
    failed: []
    PlayerSpec.js (line 15)
    failed: []
    PlayerSpec.js (line 15)
    

    这个问题对我来说是一段旅程。很遗憾,我必须继续做其他事情。

    我真诚地希望这可以解决您的问题,或者至少为您指明正确的方向。希望它也能帮助其他人。

    祝你好运!

    【讨论】:

    • 哇,非常感谢您为此付出的所有努力。我需要一点时间来消化这个并真正了解发生了什么以及它是否解决了我的问题。至少,这是我见过的最接近 Jasmine 内部组件的方法,就像我们在 1.3 版中那样。
    • 哇...我花了很长时间才回来,对此感到抱歉。我对您提出的开箱即用解决方案印象深刻。我当然宁愿不必直接修改 Jasmine,但我接受这是最好的(假设是唯一的)解决方案。但是,无论如何,对此的需求只是调试信息,所以我想我现在会坚持使用香草茉莉花。非常感谢您为此付出的所有努力。
    • 我现在正在尝试类似的东西,但似乎jsApiReporter 没有立即得到结果,所以在他们的afterEach 期间只有大约一半的规范可以得到规范结果。这是 2.4.1。
    • 也许jsApiReporter.specs() 会更有帮助
    【解决方案3】:

    我仍在使用 Jasmine 1.2,所以 Jasmine 2.0 中的情况可能有所不同。

    在您的 afterEach 函数中,您应该能够访问刚刚完成的当前规范:

    var currentSpec = jasmine.getEnv().currentSpec;
    

    这将返回一个具有许多属性的对象。其中之一是通过了多少嵌入式测试(results_.passedCount)。

    您可以针对该值进行测试并适当地执行日志记录。

    祝你好运!

    【讨论】:

    • 在寻找答案时,我会遇到与您发布的类似的代码,但从 Jasmine 2.0 开始,他们删除了 currentSpec 属性,因此我无法再使用它这边。
    • 我刚刚下载了 2.3.4 版并运行了我的回复中列出的命令。 jasmine.getEnv() 对象上仍有一个 currentSpec 属性。如果它在 2.2 版中被删除,它现在又回到了 2.3.4 版中。您可以通过在 afterEach 函数中使用简单的 console.log 消息来验证是否存在。当我在本地机器上运行它时,它显示了 currentSpec。
    • 我也刚升级到 2.3.4,希望如此。但是当我在我的afterEach() 中运行console.log(jasmine.version + ' ' + jasmine.getEnv().currentSpec) 时,我得到2.3.4 undefined。我很好奇你怎么能看到它......
    • 尝试使用console.log(jasmine.version, jasmine.getEnv().currentSpec); currentSpec 是一个对象。它应该可以在 FireBug 或 Chrome/IE 的开发者控制台中查看。我从不在 console.log 中连接值,我只是用逗号分隔它们。 ::耸肩::
    • 我看到了你现在所说的行为。我从简单的香草设置开始,并尝试使用 Player 规范。我的项目测试环境是高度定制的。我从一个页面为我的所有库运行测试。让我仔细看一下,看看我是否在某个地方修改了茉莉花的行为。很抱歉造成混乱。
    【解决方案4】:

    我想在 jasmine 2.5.2 上做类似的事情(有自定义记录器对象,只有在测试失败时才会打印出来,而不必手动执行)。

    通过 beforeEach/afterEach 进行了相当大的努力使其能够正常工作,最后我屈服于一个更丑陋的解决方案

    // logger print on fail
    
    function collectSpecs(suite: jasmine.Suite): jasmine.Spec[] {
        const result: jasmine.Spec[] = [];
        const process = [suite];
        while (process.length) {
            const suite = process.pop();
            const children = <jasmine.SuiteOrSpec[]> <any> suite.children; // wrong jasmine typing
            children.forEach(item => {
                switch (item.constructor.name) {
                    case "Suite":
                        process.push(<jasmine.Suite>item);
                        break;
                    case "Spec":
                        result.push(<jasmine.Spec>item);
                        break;
                }
            });
        }
        return result;
    }
    
    function findSpec(specId: string): jasmine.Spec {
        const rootSuite: jasmine.Suite = jasmine.getEnv()["topSuite"]();
        return collectSpecs(rootSuite)
            .filter(s => `${s.id}` === specId)[0];  // wrong jasmine typing on id
    }
    
    const loggerSpecProperty = "logger";
    
    function createReporter(): jasmine.CustomReporter {
        return {
            specDone: (result: jasmine.CustomReporterResult) => {
                const spec = findSpec(result.id);
                if (result.failedExpectations.length) {
                    const logger: modLog.MemoryLogger = spec[loggerSpecProperty];
                    if (logger) {
                        console.log(`\nfailed spec logger:\n${logger.lines.join("\n")}`);
                    }
                }
                delete spec[loggerSpecProperty];
            }
        };
    }
    
    export function registerReporter(): void {
        jasmine.getEnv().addReporter(createReporter());
    }
    
    function createLogger(): modLog.MemoryLogger {
        return new modLog.MemoryLogger(modLog.LogLevel.debug);
    }
    
    interface IItCallback {
        (done?: Function): void;
    }
    
    interface IItFunctionTyping {
        (name: string, callback: IItCallback): void;
    }
    
    interface IItFunction {
        (name: string, callback: IItCallback): jasmine.Spec;
    }
    
    // bad typings on it/xit/fit, actually returns Spec but is typed as void
    export function lit(fnIt: IItFunctionTyping, name: string, callback: IItCallback): jasmine.Spec {
        function inner(spec: jasmine.Spec, done?: Function) {
            const log = createLogger();
            this.log = log;
            spec[loggerSpecProperty] = log;
            callback.call(this, done);
        }
        const itFunc = <IItFunction> (fnIt || it);
        if (callback.length) {
            const spec = itFunc(name, function (done) {
                inner.call(this, spec, done);
            });
            return spec;
        } else {
            const spec = itFunc(name, function () {
                inner.call(this, spec);
            });
            return spec;
        }
    }
    

    由于@types/jasmine 掩盖了实际实现的一些细节(我想这是故意的,键入版本与 jasmine 包版本匹配),因此出现了一些不必要的类型 mumbo jumbo,但我也想练习我的 TypeScript

    传递“it”函数以在需要时仍然允许 xit/fit modLog 是我的记录器模块,覆盖它以满足您的需求

    用法:

    而不是

    it("should do something", function (done) {
        done();
    });
    

    使用

    lit(it, "should do something", function (done) {
        this.log.debug("test");
        fail("test output");
        done();
    });
    

    (没有很好的记录,但我认为你可以得到图片)

    如果 customReporter 有办法访问规范上下文会更好

    (那么这一切基本上都只是为了调试目的,你也可以将 console.log 添加到特定的测试中,当它失败并且你正在为细节而苦恼时,但是了解 jasmine 是很有趣的练习更多)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      • 2021-06-05
      • 1970-01-01
      相关资源
      最近更新 更多