簡體   English   中英

在 Jest 中,如何使測試失敗?

[英]In Jest, how can I make a test fail?

我知道我可以從測試內部拋出一個錯誤,但我想知道是否有類似 Jasmine 提供的全局fail()方法?

Jest 實際上使用了 Jasmine,所以你可以像以前一樣使用fail

示例調用:

fail('it should not reach here');

這是 Jest 的 TypeScript 聲明文件中的定義:

declare function fail(error?: any): never;

如果你知道某個特定的調用應該失敗,你可以使用expect

expect(() => functionExpectedToThrow(param1)).toThrow();
// or to test a specific error use
expect(() => functionExpectedToThrow(param1)).toThrowError();

有關傳入字符串、正則表達式或 Error 對象以測試toThrowError方法中的預期錯誤的詳細信息,請參閱Jest 文檔

對於異步調用,請使用.rejects

// returning the call
return expect(asyncFunctionExpectedToThrow(param1))
  .rejects();
// or to specify the error message
// .rejects.toEqual('error message');

使用 async/await 您需要使用 async 標記測試功能

it('should fail when calling functionX', async () => {
  await expect(asyncFunctionExpectedToThrow(param1))
    .rejects();
  // or to specify the error message
  // .rejects.toEqual('error message');
}

請參閱.rejects教程中的文檔。

另請注意,Jest 的未來版本中可能會刪除 Jasmine fail功能,請參閱 Yohan Dahmani 的評論。 您可以開始使用上面的expect方法,或者使用throw new Error('it should not reach here');進行查找和替換fail 如其他答案所述。 如果你更喜歡fail的簡潔性和可讀性,如果 Jasmine 從 Jest 中刪除,你總是可以創建自己的函數。

function fail(message) {
  throw new Error(message);
}

你可以通過拋出錯誤來做到這一點。 例如:

test('Obi-Wan Kenobi', () => {
  throw new Error('I have failed you, Anakin')
})

復制/意大利面失敗測試:

it('This test will fail', done => {
  done.fail(new Error('This is the error'))
})

在某些情況下,某些答案將不起作用。 async-await的世界中,這樣的 try-catch 邏輯是很常見的。

try {
  await someOperation();
} catch (error) {
  expect(error.message).toBe('something');
}

現在想象一下,如果someOperation()以某種方式通過了,但您預計它會失敗,那么這個測試仍然會通過,因為它從未進入 catch 塊。 所以我們想要的是確保如果 someOperation 沒有拋出錯誤則測試失敗。

所以現在讓我們看看哪些解決方案有效,哪些無效。

接受的答案在這里不起作用,因為拋出將再次被捕獲。

try {
  await someOperation();
  throw new Error('I have failed you, Anakin');
} catch (error) {
  console.log('It came here, and so will pass!');
}

true === false 的答案也不起作用,因為斷言也會引發類似上面的錯誤,該錯誤將被捕獲。

try {
  await someOperation();
  expect(true).toBe(false); // This throws an error which will be catched.
} catch (error) {
  console.log('It came here, and so will pass!');
}

對於這種情況,一種可行的解決方案(如@WhatWouldBeCool 的回答所示)如下。 現在它明確地沒有通過測試。

try {
  await someOperation();
  fail('It should not have come here!')
} catch (error) {
  console.log('It never came here!');
}

2022 年 5 月更新

Jest 不再正式支持fail()函數。 相反,您可以做幾件事來明確地失敗。

方法一

您可以將您的 promise 函數包裝在 expect 中,並告訴 jest 該函數應該拒絕給定錯誤。 如果someOperation()以某種方式通過,jest 將拋出錯誤。 如果someOperation()因您指定之外的任何其他原因而失敗,它將引發錯誤。 除了toThrowError()之外,您還可以使用其他不同的方法。

await expect(someOperation()).rejects.toThrowError('error!')

方法二

您可以在測試中明確聲明您期望的斷言數量。 如果由於someOperation()從未失敗而不匹配,則 jest 將引發錯誤。

expect.assertions(1)

try {
  await someOperation();
} catch (error) {
  expect(error.message).toBe('something');
}

不要認為有,在這里討論: https ://github.com/facebook/jest/issues/2129

這里有很多好主意。 僅添加有關測試異步代碼的額外信息,這可能導致嘗試使 Jest 顯式失敗,請查看Testing Asynchronous Code的文檔https://jestjs.io/docs/en/asynchronous

要測試一個返回解析的 Promise 的函數,返回 Promise 很重要,因此 Jest 知道只有在 Promise 解析或超時時才完成測試:

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter')
  })
})

要測試返回拒絕的 Promise 的函數,返回 Promise 很重要,因此 Jest 知道只有在 Promise 被拒絕或超時時才進行測試。 並且還必須說明 Jest 需要計算多少個斷言,否則如果 Promise 被解決,它就不會失敗——在這種情況下這是錯誤的——:

test('the fetch fails with an error', () => {
  expect.assertions(1)
  return fetchData().catch(e => expect(e).toMatch('some specific error'))
})

你總是可以做這樣的事情:)

expect(true).toBe(false);

添加 jest-fail-on-console npm 包,然后在您的 jest.config.js 上

import failOnConsole from 'jest-fail-on-console'

failOnConsole();

一旦由於測試項目中拋出錯誤或警告而由 jest 完成控制台錯誤或警告,這將導致測試失敗。

如果您將字符串傳遞給它,傳遞給每個測試的完成回調將引發錯誤。

例如

it('should error if the promise fails', async (done) => {
try {
  const result = await randomFunction();

  expect(result).toBe(true);

  done();
} catch (e) {
  done('it should not be able to get here');
}

});

在下面的代碼中,如果 randomFunction 拋出錯誤,它將被捕獲並自動失敗,因為字符串被傳遞給 done。

我剛遇到這個,經過一番挖掘,我找到了問題的根源。

Jest 自成立以來一直與 Jasmine 兼容。Jasmine 提供了fail function 以編程方式使測試失敗。 這對於拋出錯誤會導致測試錯誤通過的情況非常有用(過度簡化的示例,但希望能說明用例):

function alwaysThrows() {
  throw new Error();
}

describe('alwaysThrows', () => {
  it('should throw', () => {
    try {
      alwaysThrows();
      // here if there is nothing to force a failure, your
      // test could "pass" as there are no failed expectations
      // even though no error was thrown. If you just put the
      // following to prevent that, you actually force the test
      // to always pass:
      throw new Error('it should have failed');
      // that's why instead you use Jasmine's `fail(reason)` function:
      fail('it should have failed');
    } catch(err) {
      expect(err).toBeDefined();
    }
  });
)
});

所以,發生的事情是這樣的:

  • 最初 Jest 確實定義了一個fail() function ,因為它的默認測試運行器是jest-jasmine2 ,它提供了fail()
  • 在 Jest 版本 27(或左右)中,Jest 將jest-jasmine2替換為jest-circus作為默認測試運行器。 jest-circus沒有實現fail() function。這在 2021 年 7 月 28 日被報告為錯誤: https://github.com/facebook/jest/issues/11698
  • Jest 的類型定義(在 DefinitelyTyped 中維護)沒有刪除fail() function,所以自動完成和 TypeScript 編譯器仍然認為它存在並且可以使用。 DefinitelyTyped 中也存在一個問題: https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/55803這個線程的問題是他們決定不從類型定義中刪除它,因為它被標記為Jest 存儲庫中的“回歸”。 不幸的是,Jest 存儲庫的線程沒有關於他們將來是否支持這一點的官方回應,因此類型定義處於不確定狀態。

所以,長話短說,Jest 默認不支持fail() fail()但知道這是默認任務運行程序的問題,您可以通過告訴 Jest 使用jest-jasmine2而不是默認jest-circus賽跑者:

  • npm i -D jest-jasmine2
  • 配置 Jest 配置:
     module.exports = { testRunner: "jest-jasmine2" };

PS:通常有比try / catch更好的方法來解決實際測試用例中的錯誤。 您可以在此處查看在同步和異步上下文中不需要try / catch的不同方式處理錯誤的示例: https://gist.github.com/joeskeen/d9c053b947e5e7462e8d978286311e83

您可以拋出一個模擬應用程序拋出的錯誤的錯誤,然后期望它的消息與實際不同。

        try {
            await somthingYouExpectToFail();
            throw new Error("Fail!");
        } catch (error) {
            expect(error.message).not.toBe("Fail!");
        }
    

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM