使用React,Redux和Router进行真正的集成测试
by Marcelo Lotif
通過馬塞洛·洛蒂夫(Marcelo Lotif)
使用React,Redux和Router進(jìn)行真正的集成測(cè)試 (Real integration tests with React, Redux and Router)
After being bitten a couple of times by bad refactoring and a broken app?—?even with all my tests green?—?I started to research about integration tests in React. Possibly also with Redux and React Router.
在經(jīng)歷了糟糕的重構(gòu)和壞掉的應(yīng)用程序幾次咬傷之后,即使我的所有測(cè)試都是綠色的,我也開始研究React中的集成測(cè)試。 可能還可以使用Redux和React Router。
To my absolute shock, I couldn’t find any good material out there. The ones I found either were doing incomplete integration tests or simply doing it the wrong way.
令我震驚的是,我找不到任何好的材料。 我發(fā)現(xiàn)這要么是在進(jìn)行不完整的集成測(cè)試,要么就是以錯(cuò)誤的方式進(jìn)行。
So here we’re going to build an integration test that initializes a React component, fires a simulated user interaction and assert that our component changes the way we expect it to change.
因此,這里我們將構(gòu)建一個(gè)集成測(cè)試,該測(cè)試將初始化一個(gè)React組件,觸發(fā)一個(gè)模擬的用戶交互,并斷言我們的組件改變了我們期望它改變的方式。
What this is not about: unit testing. I’m not going to dive into this right now, but there is a very good reason we at Wave (we’re hiring, by the way!) are slowing down on our unit tests and switching to integration tests. Scroll to the bottom if you’re interested in that.
這不是關(guān)于:單元測(cè)試。 我現(xiàn)在不打算深入探討這個(gè)問題,但是有一個(gè)很好的理由說明我們Wave的速度 ( 我們正在招聘 ,順便說一句!)正在減慢我們的單元測(cè)試并切換到集成測(cè)試。 如果對(duì)此感興趣,請(qǐng)滾動(dòng)到底部。
Disclosure: I wouldn’t have had those tests working as smoothly as they are now if it wasn’t for the great front end folks at Wave, especially the amazing Tommy Li who figured out how to connect the router, so thank you!
披露:如果不是Wave的優(yōu)秀前端人員,尤其是那些想出如何連接路由器的驚人的Tommy Li ,那我將沒有那些測(cè)試能夠像現(xiàn)在這樣平穩(wěn)地工作,所以謝謝!
配置 (Setting up)
For this project, we are going to use React, Redux, React/Redux Router (optional) and Thunk (optional) to run the app, Jest and Enzyme for testing.
對(duì)于這個(gè)項(xiàng)目,我們將使用React , Redux , React / Redux Router (可選)和Thunk (可選)來運(yùn)行應(yīng)用程序, Jest和Enzyme進(jìn)行測(cè)試。
I’ll skip the setup of all those since there are many great tutorials out there about that.
我將跳過所有這些設(shè)置,因?yàn)槟抢镉泻芏嗪馨舻慕坛獭?
To set up the basics of my integration test, I’m gonna cheat a little bit and create an util function with some boilerplate code:
為了建立集成測(cè)試的基礎(chǔ)知識(shí),我將作弊一點(diǎn),并使用一些樣板代碼創(chuàng)建util函數(shù):
測(cè)試中 (Testing)
In your test file, you will first need to import some dependencies, your reducer and your component:
在測(cè)試文件中,首先需要導(dǎo)入一些依賴項(xiàng),reducer和組件:
Then, on the beforeEach function, set up your integration test variables using that util function:
然后,在beforeEach函數(shù)上,使用該util函數(shù)設(shè)置集成測(cè)試變量:
(If you don’t use React Router or Thunk, you can just remove their references here and on the util function and it’s going to work the same way.)
(如果您不使用React Router或Thunk,則可以在此處和util函數(shù)上刪除它們的引用,并且它們將以相同的方式工作。)
Now you’re all set to mount your component and test it. Let’s imagine this component renders a div, which displays a text coming from the reducer. When clicking on it, the text should change to another string, let’s say ‘new text’. To test that interaction, you can simply do:
現(xiàn)在您已經(jīng)準(zhǔn)備好安裝組件并對(duì)其進(jìn)行測(cè)試。 讓我們想象一下這個(gè)組件渲染了一個(gè)div ,它顯示了來自reducer的文本。 單擊它時(shí),文本應(yīng)更改為另一個(gè)字符串,例如“新文本”。 要測(cè)試這種交互,您可以簡(jiǎn)單地執(zhí)行以下操作:
That’s it ? With this very simple code you’re testing the div calling an action producer on click, that dispatches an action to the reducer, that changes the data, triggering a re-render on the component, that is expected to change the way you want it to change. If any of those steps fail, your test goes red and you know that functionality of your app is not working.
就是這樣?通過這個(gè)非常簡(jiǎn)單的代碼,您正在測(cè)試div并在單擊時(shí)調(diào)用一個(gè)動(dòng)作生成器,該動(dòng)作生成器將動(dòng)作分派給reducer,該動(dòng)作將更改數(shù)據(jù),觸發(fā)組件的重新渲染,從而有望改變方式你想改變它。 如果這些步驟中的任何一個(gè)失敗,則測(cè)試會(huì)變成紅色,并且您知道應(yīng)用程序的功能無法正常工作。
You can try to go deeper in this chain and assert some other things:
您可以嘗試深入了解此鏈并斷言其他一些事情:
測(cè)試API調(diào)用 (Testing API calls)
In the real world you’ll probably need to call some APIs to fetch data for your app, and that is the part you need to mock in order to test things effectively. We’ll use Jest here, which is not the best way to mock http requests, but I’ll do it for the convenience.
在現(xiàn)實(shí)世界中,您可能需要調(diào)用一些API來獲取應(yīng)用程序的數(shù)據(jù),而這是您為了進(jìn)行有效測(cè)試而需要模擬的部分。 我們將在這里使用Jest,這不是模擬HTTP請(qǐng)求的最佳方法,但是為了方便起見,我將使用它。
Assuming you use a hypothetical http client to call an endpoint through its get function when you click on the div, then set the return of this call into the reducer that gets displayed back in the div:
假設(shè)您在單擊div時(shí)使用假設(shè)的http客戶端通過其get函數(shù)調(diào)用端點(diǎn),然后將此調(diào)用的返回值設(shè)置到在div中顯示的reducer中:
In an even more real world application, that get function will return you a Promise object. Things become a little complicated from here because the simulated click function is unaware of that promise and there is no way of executing its then function. The reference to the object has been lost.
在更真實(shí)的應(yīng)用程序中,該get函數(shù)將返回一個(gè)Promise對(duì)象。 從這里開始,事情變得有些復(fù)雜,因?yàn)槟M的click函數(shù)沒有意識(shí)到那個(gè)承諾,并且無法執(zhí)行then函數(shù)。 對(duì)對(duì)象的引用已丟失。
We will need to somehow wait for that promise to resolve before executing the assertions. We work around this by doing a little hack in an util function:
在執(zhí)行斷言之前,我們將需要以某種方式等待該承諾解決。 我們通過在util函數(shù)中進(jìn)行一些修改來解決此問題:
And our test is now going to look like this:
現(xiàn)在,我們的測(cè)試將如下所示:
With the async … await statement , available since ES7, our test is going to wait until all promises have been resolved so it can make its assertions. Jest currently has no solution for this, but this hack works pretty well in real life.
自從ES7開始使用async…await語句,我們的測(cè)試將等待直到所有promise都已解決,以便可以進(jìn)行聲明。 Jest目前還沒有解決方案,但是此hack在現(xiàn)實(shí)生活中效果很好。
If you have more complicated action producers with other promises being called in the resolve or reject of that first promise, I suggest you unit test those calls and also test the final results of all cases in integration tests.
如果您有更復(fù)雜的動(dòng)作生產(chǎn)者,而在第一個(gè)承諾的解決或拒絕中調(diào)用了其他承諾,則建議您對(duì)這些調(diào)用進(jìn)行單元測(cè)試,并在集成測(cè)試中測(cè)試所有案例的最終結(jié)果。
更多測(cè)試 (More Testing)
In case you need to set an initial state to your component , you can dispatch actions manually until you reach the desired state:
如果需要為組件設(shè)置初始狀態(tài),則可以手動(dòng)分派操作,直到達(dá)到所需狀態(tài)為止:
store.dispatch({ payload: 'data', type: 'SOME_ACTION' });You can also go crazy on those assertions and test every little thing, or keep it simple knowing the test coverage is going to be the same as if you have added unit tests on each of the layers of this app, but with a lot less code. In addition, you are also testing how those layers connect with each other and how your app responds to user input and data store changes.
您也可以為這些斷言而瘋狂,測(cè)試每件事,或者保持簡(jiǎn)單,因?yàn)橹罍y(cè)試覆蓋范圍與在此應(yīng)用程序的每個(gè)層上都添加了單元測(cè)試一樣,但是代碼卻少得多。 此外,您還將測(cè)試這些層如何相互連接以及您的應(yīng)用如何響應(yīng)用戶輸入和數(shù)據(jù)存儲(chǔ)更改。
Please leave your opinion in the comments section, there is a lot of improvements to be made here and I’m happy to modify this according to your suggestions. Thanks!
請(qǐng)?jiān)谠u(píng)論部分中留下您的意見,這里有很多改進(jìn)之處,我很樂意根據(jù)您的建議進(jìn)行修改。 謝謝!
NO沒有單元測(cè)試?!? (Y U NO UNIT TEST?!?)
We at Wave (did I mention we’re hiring?) have done a ton of front end unit tests before and, to be honest, the majority of them have been somewhat useless. Sure, they are at the core of TDD, but some reducers and action producers unit tests are just boilerplate code and don’t add much value to the code or the TDD process.
Wave之前 ( 我們是否提到過要聘用我們嗎?)之前, 我們已經(jīng)進(jìn)行了大量的前端單元測(cè)試,老實(shí)說,大多數(shù)測(cè)試都沒有用。 當(dāng)然,它們是TDD的核心,但是某些化簡(jiǎn)工具和動(dòng)作生產(chǎn)者單元測(cè)試只是樣板代碼,不會(huì)為代碼或TDD流程增加太多價(jià)值。
You can actually do really good TDD with integration tests only, and they are going to be useful in the future to spot broken links between your app layers and ultimately to check if your app is behaving as expected, which is what automated tests are for.
實(shí)際上,您只能使用集成測(cè)試來做真正好的TDD,并且它們?cè)趯韺⒑苡杏?#xff0c;可以發(fā)現(xiàn)您的應(yīng)用程序?qū)又g斷開的鏈接,并最終檢查您的應(yīng)用程序的行為是否符合預(yù)期,這就是自動(dòng)化測(cè)試的目的。
Don’t get me wrong, we still unit test edge cases that are too complicated or annoying to reproduce on integration tests, but the majority of our unit tests became useless as soon as we added integration tests like the above. In the end, it means the time we now spend thinking about, developing and fixing tests is a lot lower than it was before and they are much more effective in spotting problems in the app. So, win win ?
別誤會(huì),我們?nèi)匀粚?duì)過于復(fù)雜或煩人的邊緣測(cè)試進(jìn)行單元測(cè)試,以至于無法在集成測(cè)試中重現(xiàn),但是一旦添加了上述集成測(cè)試,我們的大多數(shù)單元測(cè)試就變得毫無用處。 最后,這意味著我們現(xiàn)在花在思考,開發(fā)和修復(fù)測(cè)試上的時(shí)間比以前少了很多,并且它們?cè)诎l(fā)現(xiàn)應(yīng)用程序中的問題上更加有效。 所以,雙贏?
One problem you might find is with deep mounting, instead of shallow rendering. You might think some component trees are too complicated to mount, but I’ll say another advantage of mounting the root component is to test if the child components are being instantiated correctly. If you have connected child components, you can test them separately if you prefer. I haven’t tried shallow rendering a connected component to see if this integration test setup still works, but you can try. If you don’t like to mount and don’t have connected child components, another possibility I haven’t explored is shallow render and then manually connecting them. The important thing here is to feel comfortable with the amount and the quality of the tests you’re writing, making sure they actually help in automatically doing some regression testing and discovering hidden issues for you.
您可能會(huì)發(fā)現(xiàn)的一個(gè)問題是深層安裝而不是淺層渲染。 您可能會(huì)認(rèn)為某些組件樹太復(fù)雜而無法掛載,但是我會(huì)說掛載根組件的另一個(gè)好處是測(cè)試子組件是否被正確實(shí)例化。 如果已連接子組件,則可以根據(jù)需要單獨(dú)測(cè)試它們。 我沒有嘗試淺化呈現(xiàn)連接的組件以查看此集成測(cè)試設(shè)置是否仍然有效,但是您可以嘗試。 如果您不喜歡掛載并且沒有連接子組件,那么我還沒有探討的另一種可能性是淺渲染,然后手動(dòng)連接它們。 這里重要的是讓您對(duì)正在編寫的測(cè)試的數(shù)量和質(zhì)量感到滿意,確保它們實(shí)際上有助于自動(dòng)執(zhí)行一些回歸測(cè)試并為您發(fā)現(xiàn)隱藏的問題。
翻譯自: https://www.freecodecamp.org/news/real-integration-tests-with-react-redux-and-react-router-417125212638/
總結(jié)
以上是生活随笔為你收集整理的使用React,Redux和Router进行真正的集成测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到已故亲人活过来代表什么
- 下一篇: img 加载 svg占位符_如何使用SV