测试驱动开发 测试前移_我如何以及为什么认为测试驱动开发值得我花时间
測(cè)試驅(qū)動(dòng)開(kāi)發(fā) 測(cè)試前移
by Ronauli Silva
通過(guò)羅納利·席爾瓦(Ronauli Silva)
I first read about test driven development (TDD) in some technical reviews blog, but I barely read it (or thought about it). Why would people write tests first when they already knew the logic?
我首先在一些技術(shù)評(píng)論博客中閱讀了有關(guān)測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD)的信息,但幾乎沒(méi)有閱讀(或考慮過(guò))。 人們?yōu)槭裁?strong>已經(jīng)知道邏輯就為什么要先寫(xiě)測(cè)試?
So what was this all about? Writing tests first, incrementally building the logic, and doing it in iterations. The funny thing is, when you give two programmers five minutes to code a simple fibonacci sequence and ask one to do TDD, by the end of the 5 minutes, the programmer doing TDD may say “I have test for it!” But they won’t have finished the code. On the other hand, the other one will have finished the entire fibonacci sequence and will have optimized it.
那到底是什么呢? 首先編寫(xiě)測(cè)試,逐步構(gòu)建邏輯,然后進(jìn)行迭代。 有趣的是,當(dāng)您給兩個(gè)程序員五分鐘的時(shí)間來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的斐波那契序列并要求一個(gè)人進(jìn)行TDD時(shí),在5分鐘結(jié)束時(shí),執(zhí)行TDD的程序員可能會(huì)說(shuō):“我已經(jīng)對(duì)此進(jìn)行了測(cè)試!” 但是他們不會(huì)完成代碼。 另一方面,另一個(gè)將完成整個(gè)斐波那契數(shù)列并對(duì)其進(jìn)行優(yōu)化。
為什么要使用TDD? 單元測(cè)試不夠好嗎? (Why use TDD? Aren’t unit tests good enough?)
At the end of last year, I finally met TDD face to face. In a three-month bootcamp session, we were forced to always do things with TDD. I was already struggling enough, and so my brain always rebelled when it came time to write the tests.
去年年底,我終于與TDD面對(duì)面了。 在為期三個(gè)月的訓(xùn)練營(yíng)會(huì)議中,我們被迫始終使用TDD進(jìn)行操作。 我已經(jīng)很掙扎了,所以到了編寫(xiě)測(cè)試的時(shí)候,我的大腦總是反叛。
Why should we write tests first when I can directly code the logic, my brain asked? Can’t we just write them later? After all functionality is finished?
我的大腦問(wèn),當(dāng)我可以直接編寫(xiě)邏輯代碼時(shí),為什么要先編寫(xiě)測(cè)試? 我們不能稍后再寫(xiě)嗎? 所有功能完成之后?
Let me give you a quick overview of TDD in a nutshell.
讓我簡(jiǎn)要概述一下TDD。
Let’s say I’m creating a fibonacci function. I might ask, what is the simplest assertion on a fibonacci? => Returns 1 if input is 1.
假設(shè)我要?jiǎng)?chuàng)建一個(gè)斐波那契函數(shù)。 我可能會(huì)問(wèn),關(guān)于斐波那契的最簡(jiǎn)單的斷言是什么? =>如果輸入為1,則返回1。
What is the simplest solution for that assertion? The simplest solution, I mean it.
該斷言最簡(jiǎn)單的解決方案是什么? 最簡(jiǎn)單的解決方案 我是認(rèn)真的。
Now, next move. What is next simplest assertion for fibonacci?=> Returns 2 for inputs = 3
現(xiàn)在,下一步。 斐波那契的下一個(gè)最簡(jiǎn)單的斷言是什么?=>輸入2返回2 = 3
Again, let’s fix this very quickly. Just return it and add some branching.
同樣,讓我們??快速修復(fù)此問(wèn)題。 只需返回它并添加一些分支即可。
Move to another expectation. Aim for a bigger number. Do it iteratively, incrementally.
移到另一個(gè)期望。 爭(zhēng)取更大的數(shù)量。 逐步進(jìn)行迭代。
On and on it goes, until you get the nice solution for your fibonacci function. If you want to practice more, try adding memoization during the process (and don’t forget—with TDD).
不斷進(jìn)行下去,直到您獲得斐波那契函數(shù)的理想解決方案為止。 如果您想練習(xí)更多,請(qǐng)嘗試在此過(guò)程中添加備忘(不要忘了-使用TDD)。
Did you notice what we did there? The baby steps, your assertion, and how we define the solution? Your thought process got separated into these five critical points:
您注意到我們?cè)谀抢镒隽耸裁磫?#xff1f; 嬰兒的腳步,您的主張以及我們?nèi)绾味x解決方案? 您的思考過(guò)程分為以下五個(gè)關(guān)鍵點(diǎn):
Simple & Incremental Design — You have to think about what is the simplest thing a particular function could do, and what’s coming next. The fibonacci example describes this point perfectly.
簡(jiǎn)單和增量設(shè)計(jì)-您必須考慮某個(gè)特定功能可以做的最簡(jiǎn)單的事情,以及下一步的工作。 斐波那契示例很好地描述了這一點(diǎn)。
Assertion — What is your expectation of that function? And how do you describe that expectation? Will other people understand it quickly?Some test libraries provide you with a test description feature. That string is the only verbose thing that explains what your code is doing.
斷言-您對(duì)該功能有什么期望? 您如何描述這種期望? 其他人會(huì)很快理解嗎?某些測(cè)試庫(kù)為您提供測(cè)試描述功能。 該字符串是解釋您的代碼正在執(zhí)行的唯一冗長(zhǎng)的操作。
Make sure it’s a good explanation, or you’ll get a call on your holiday because your unreadable test case is failing, and no one knows why.
確保這是一個(gè)很好的解釋,否則您的假期會(huì)打來(lái)電話,因?yàn)槟鸁o(wú)法讀取的測(cè)試用例失敗了,沒(méi)人知道原因。
Testable Design — How should you design it so it can be testable? Take a look at these two snippets below.
可測(cè)試的設(shè)計(jì) -應(yīng)該如何設(shè)計(jì)它以便可測(cè)試? 看看下面的這兩個(gè)片段。
The first one:
第一個(gè):
By doing TDD, since you write the test first, you have to make sure that your code is testable. You can see from the example that you don’t even test your fibonacci function. Instead, you test the side-effect of that fibonacci logic in your code, which invokes the console.log function.
通過(guò)執(zhí)行TDD,由于您首先編寫(xiě)了測(cè)試,因此必須確保您的代碼是可測(cè)試的 。 從示例中可以看到,您甚至沒(méi)有測(cè)試斐波那契函數(shù)。 而是在代碼中測(cè)試該斐波那契邏輯的副作用 ,該邏輯調(diào)用console.log函數(shù)。
The other thing is, you never know which one is failing, the console.log() or your fibonacci block when you refactor it. In this way, TDD leads us to increase modularity in our code.
另一件事是,當(dāng)您重構(gòu)它時(shí),您永遠(yuǎn)都不知道哪個(gè)是失敗的console.log()或您的fibonacci塊。 通過(guò)這種方式,TDD使我們提高了代碼的模塊化程度。
Now, let’s look at second snippet.
現(xiàn)在,讓我們看看第二個(gè)片段。
In the second example, we can see that we test the particular fibonacci function, not the other function that spikes on it. We are confident that the function works perfectly under the conditions that we state. We are sure that if the other function invokes our fibonacci and fails, it is not from our code.
在第二個(gè)示例中,我們可以看到我們測(cè)試了特定的斐波那契函數(shù),而不是其他尖峰函數(shù)。 我們相信該功能在我們聲明的條件下可以完美運(yùn)行。 我們確定如果另一個(gè)函數(shù)調(diào)用我們的斐波那契并失敗,則不是來(lái)自我們的代碼。
Negatives and Corner Cases — what do you expect when something’s not right: is it invoked with null? Does it throw an exception? How should it be handled? What could possibly happen in the code? What could be the strangest and weirdest thing that could happen in this loop? What test can catch that?
否定情況和極端情況 –如果出現(xiàn)不正確的情況,您會(huì)期望什么:使用null調(diào)用嗎? 它會(huì)引發(fā)異常嗎? 應(yīng)該如何處理? 代碼中可能會(huì)發(fā)生什么? 在此循環(huán)中可能發(fā)生的最奇怪和最奇怪的事情是什么? 有什么考驗(yàn)可以抓住?
Boundaries — Should you expect that from your function? Are you sure it’s not another class’s responsibility?
邊界 -您是否應(yīng)該從職能中獲得期望? 您確定這不是另一堂課的責(zé)任嗎?
我對(duì)TDD的問(wèn)題 (My issues with TDD)
Yes, it is slow indeed. Sometimes, your time is doubled since you’re writing both tests and logic at the same time. This makes how you use your keyboard important (typing speed, better shortcut usage, and so on).
是的,確實(shí)很慢。 有時(shí),由于您同時(shí)編寫(xiě)測(cè)試和邏輯,因此您的時(shí)間增加了一倍。 這使您使用鍵盤(pán)的方式變得很重要(鍵入速度,更好的快捷方式用法等)。
And even worse —when the requirements change—you have to refactor or delete and rewrite test code you worked hard on. Which means that tests code is code you write that is more likely to be deleted in the future. And you are doing it, iteratively. DELETES. CODES. REWRITES. AGAIN. IN A LOOP!
更糟糕的是,當(dāng)需求發(fā)生變化時(shí),您必須重構(gòu)或刪除并重寫(xiě)您一直在努力的測(cè)試代碼。 這意味著測(cè)試代碼是您編寫(xiě)的代碼,將來(lái)很有可能被刪除。 而您正在迭代地這樣做。 刪除。 編碼。 重寫(xiě)。 再次。 一圈!
Think about it. Why would you write code that is more likely to be deleted?
想一想。 您為什么要編寫(xiě)更有可能被刪除的代碼?
“Nope, that’s enough of this TDD thing. I’ll do it when I find a strong reason why I should spend time writing code I’m likely to delete”, I said to myself.
“不,這個(gè)TDD夠了。 我對(duì)自己說(shuō):“當(dāng)我發(fā)現(xiàn)有充分的理由為什么我應(yīng)該花時(shí)間編寫(xiě)可能會(huì)刪除的代碼時(shí),我會(huì)做的。”
And that was right before I unconsciously started digging my own grave.
那是在我不知不覺(jué)開(kāi)始挖掘自己的墳?zāi)怪啊?/strong>
為什么我改變主意 (Why I changed my mind)
The enlightenment came about two months later, when I was assigned to a group that did not implement TDD well at all.
大約兩個(gè)月后,當(dāng)我被分配到一個(gè)完全沒(méi)有很好地執(zhí)行TDD的小組時(shí),就得到了啟迪。
I mean, they implemented TDD, but they left the tests broken. They didn’t bother to fix those failing test cases (which often broke because the requirements had changed). And this happened because of the most cliche reason in the world: they didn’t have time. They had to make deadlines.
我的意思是,他們實(shí)施了TDD, 但是卻使測(cè)試失敗了。 他們沒(méi)有費(fèi)心去修復(fù)那些失敗的測(cè)試用例(由于需求發(fā)生了變化,測(cè)試用例經(jīng)常失敗)。 發(fā)生這種情況是由于世界上最陳詞濫調(diào)的原因:他們沒(méi)有時(shí)間。 他們必須規(guī)定最后期限。
After looking at the situation, I mumbled “Look, see! This TDD doesn’t work in the production world!” It made me question many things: is this TDD worth fighting for? Is TDD worth the time? Does it even deliver any business value?
看完情況后,我喃喃地說(shuō):“看,看! 該TDD在生產(chǎn)環(huán)境中不起作用!” 這讓我提出了很多問(wèn)題:這個(gè)TDD是否值得爭(zhēng)取? TDD值得嗎? 它甚至提供任何商業(yè)價(jià)值嗎?
After a while, I realized that the problems were growing exponentially, tasks were getting delayed, chaos was reigning, and the developer experience was getting really bad — all because they implemented TDD poorly and halfheartedly. It was even worse than not writing tests at all.
過(guò)了一會(huì)兒,我意識(shí)到問(wèn)題正在成倍增長(zhǎng),任務(wù)被延遲,混亂不斷,開(kāi)發(fā)人員的經(jīng)驗(yàn)真的變得很糟糕-所有這些都是因?yàn)樗麄儗?duì)TDD的執(zhí)行不力而全力以赴。 比根本不編寫(xiě)測(cè)試還要糟糕。
Here are some of the issues it caused:
這是它引起的一些問(wèn)題:
- When I added a new feature or refactored things, I didn’t know whether that code was failing or not because the test was already failing. 當(dāng)我添加新功能或重構(gòu)事物時(shí),我不知道該代碼是否失敗,因?yàn)闇y(cè)試已經(jīng)失敗。
We were forced to have high threshold on code coverage. And make no mistake, programmers are smart and sneaky. They write tests with no expectations, like smoke tests. And that was the only test they had on that particular logic. It was like, we only knew it was failing after everything was on fire. How dangerous.
我們被迫對(duì)代碼覆蓋率設(shè)置高閾值。 毫無(wú)疑問(wèn),程序員是聰明而狡猾的 。 他們編寫(xiě)沒(méi)有期望的測(cè)試,例如冒煙測(cè)試。 那是他們對(duì)該特定邏輯進(jìn)行的唯一測(cè)試。 就像,我們只知道一切都著火之后才失敗。 多么危險(xiǎn)
- We used CI/CD for deployment. And we always deployed even though it was failing, which was scary: You never knew whether your production itself was failing, or if it was because you didn’t fix the tests. 我們使用CI / CD進(jìn)行部署。 而且,即使失敗了,我們也總是進(jìn)行部署,這很可怕:您永遠(yuǎn)不知道自己的生產(chǎn)是否失敗,或者是因?yàn)槟鷽](méi)有修復(fù)測(cè)試。
- After production, we ended up fixing strange and completely out-of-mind bugs. We had never even thought of those strange conditions before. (Ever find a situation when something in a try-catch block is failing but not throwing an exception?) 生產(chǎn)后,我們最終修復(fù)了奇怪且完全過(guò)時(shí)的錯(cuò)誤。 我們以前從未想過(guò)那些奇怪的情況。 (是否找到了try-catch塊中的某項(xiàng)失敗但沒(méi)有引發(fā)異常的情況?)
Oh, the horror!
哦,恐怖!
After analyzing the situation, doing it in iterations, and reflecting on it, I realized that TDD is actually a golden nugget. If done right, it can make us better developers.
在分析了情況,反復(fù)進(jìn)行并反思之后,我意識(shí)到TDD實(shí)際上是一個(gè)金塊。 如果做得對(duì),它可以使我們成為更好的開(kāi)發(fā)人員。
為什么我現(xiàn)在愛(ài)TDD (Why I now love TDD)
使用TDD,您的bug更少 (With TDD, you have fewer bugs)
You’ll hardly miss things that you can catch with your tests.
您幾乎不會(huì)錯(cuò)過(guò)可以通過(guò)測(cè)試掌握的東西 。
When you get a requirement, you write a test for it first. Then you run the test, and see if it fails first. When you add the logic, you see if it passes.
收到需求后,您首先要為其編寫(xiě)測(cè)試。 然后運(yùn)行測(cè)試,然后查看它是否首先失敗。 添加邏輯時(shí),您可以查看它是否通過(guò)。
Seeing it fail is important, because you know what broke your code. In the long run, this practice ensures that all lines in your code are well-tested.
看到它失敗很重要,因?yàn)槟朗裁雌茐牧四拇a 。 從長(zhǎng)遠(yuǎn)來(lái)看,這種做法可以確保代碼中的所有行都經(jīng)過(guò)良好測(cè)試。
TDD節(jié)省了很多時(shí)間(將來(lái)) (TDD saves you lot of time (in the future))
CI/CD relies heavily on tests. If you write the wrong tests (or too few tests) you already wasted five hours to find what errors it couldn’t catch. If you write good tests, and spend just five more minutes writing deeper and more complete conditions of your code, you’ll save time debugging it in the future.
CI / CD嚴(yán)重依賴測(cè)試。 如果您編寫(xiě)了錯(cuò)誤的測(cè)試(或測(cè)試太少),您已經(jīng)浪費(fèi)了五個(gè)小時(shí)來(lái)查找無(wú)法捕獲的錯(cuò)誤。 如果您編寫(xiě)了良好的測(cè)試,并且只花了五分鐘以上的時(shí)間來(lái)編寫(xiě)更深入,更完整的代碼條件,則可以節(jié)省將來(lái)調(diào)試它的時(shí)間。
TDD處理編碼的人為方面 (TDD deals with the human aspects of coding)
The main ones being negligence and forgetfulness. If you write all the logic directly, by the end of, say, line 190, you may forget why you multiplied a variable by 100 at line 19.
主要是疏忽和健忘。 如果直接編寫(xiě)所有邏輯,例如在第190行的末尾,您可能會(huì)忘記為什么在第19行將變量乘以100。
But, by doing it incrementally and stating the assertion of our code, we gradually build our understanding. This makes us understand the code and its behaviors better.
但是,通過(guò)逐步執(zhí)行并聲明代碼聲明,我們逐漸建立了理解。 這使我們更好地理解了代碼及其行為。
As a bonus, we have sort of living and functional documentation of our code. You can see which test is failing if you delete the previous line, and you instantly know why.
值得一提的是,我們還提供了一些有效的代碼文檔。 如果刪除上一行,您可以看到哪個(gè)測(cè)試失敗,并且您立即知道原因。
TDD可幫助您集中精力 (TDD helps you focus)
Programmers tend to write too much code, or write code that does too much. Or they try to plan for conditions that never exist. Often, when my team practiced pair pairing, I discovered that TDD allowed us to write less code compared to other teams that didn’t do TDD. While coding, we were focused on getting the test case passed — nothing less, nothing more.
程序員傾向于寫(xiě)太多的代碼,或者寫(xiě)太多的代碼。 或者他們?cè)噲D為不存在的情況做計(jì)劃。 通常,當(dāng)我的團(tuán)隊(duì)練習(xí)配對(duì)時(shí),我發(fā)現(xiàn)與沒(méi)有TDD的其他團(tuán)隊(duì)相比,TDD允許我們編寫(xiě)更少的代碼。 在編碼時(shí),我們專注于通過(guò)測(cè)試用例-沒(méi)什么,僅此而已。
TDD也有益于您的大腦 (TDD also benefits your brain)
You have proof of your code’s readiness for production, even before deploying it. You don’t have to worry about things you already tested for before. You don’t have to brag to your project manager about how project is going, because you can show them that the tests are passing!
您甚至可以在部署代碼之前就證明您的代碼已經(jīng)可以投入生產(chǎn)。 您不必?fù)?dān)心之前已經(jīng)測(cè)試過(guò)的東西。 您不必向項(xiàng)目經(jīng)理吹噓項(xiàng)目的進(jìn)展情況,因?yàn)槟梢韵蛩麄冏C明測(cè)試已通過(guò)!
However, TDD is not always your silver bullet. It takes time. You have to set up the project — such as the environment, mocks, and stubs — even before you start doing anything.
但是,TDD并不總是 你的銀彈。 這需要時(shí)間。 您必須在開(kāi)始做任何事情之前就設(shè)置項(xiàng)目(例如環(huán)境,模擬和存根)。
But remember, time spent on writing tests is not wasted time. It’s the time you invest now to save your time later. It’s the investment you make on the system you build, as you build code on top of more code. And you want to make its foundation as solid as possible. TDD gives you that.
但是請(qǐng)記住,花在編寫(xiě)測(cè)試上的時(shí)間不會(huì)浪費(fèi)時(shí)間。 現(xiàn)在是時(shí)候進(jìn)行投資,以節(jié)省以后的時(shí)間了。 當(dāng)您在更多代碼之上構(gòu)建代碼時(shí),這就是您對(duì)所構(gòu)建系統(tǒng)的投資。 您想使其基礎(chǔ)盡可能牢固。 TDD為您提供。
In the end, it could cost you a fortune if you don’t do TDD. It may take time, but it is good for you and your team in the long run.
最后,如果您不進(jìn)行TDD,可能會(huì)花費(fèi)您一筆巨款。 這可能會(huì)花費(fèi)一些時(shí)間,但從長(zhǎng)遠(yuǎn)來(lái)看,這對(duì)您和您的團(tuán)隊(duì)都是有好處的。
翻譯自: https://www.freecodecamp.org/news/test-driven-development-i-hated-it-now-i-cant-live-without-it-4a10b7ce7ed6/
測(cè)試驅(qū)動(dòng)開(kāi)發(fā) 測(cè)試前移
總結(jié)
以上是生活随笔為你收集整理的测试驱动开发 测试前移_我如何以及为什么认为测试驱动开发值得我花时间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 梦到了前任是什么预示
- 下一篇: 梦到跟人家吵架是什么预兆