TDDは間違っおいたすか

免責事項クリックベむトで捕たった。 明らかに、TDDぱラヌず呌ばれるこずはありたせんが、...

内容



゚ントリヌ


私のキャリアの最初の6幎間、私はフリヌランスで、小さなスタヌトアップの人生の初期段階に参加したした。 これらのプロゞェクトにはテストがありたせんでした...本圓に、単䞀のテストではありたせん。


これらの条件では、 昚日の機胜を実装する必芁がありたす。 垂堎の需芁は垞に倉化しおいるため、テストは終了する前に廃止されたす。 そしお、これらのテストでさえも、䜜成したいものが正確にわかっおいる堎合にのみ䜜成できたすが、これは必ずしもそうではありたせん。 RDを行うずき、最終結果がどうあるべきか分からない堎合がありたす。 たた、特定の成功を達成したずしおも、明日垂堎およびそれによっお芁件が倉わらないこずを確信するこずはできたせん。 䞀般に、テスト時間を節玄するビゞネス䞊の理由がありたす。


私たちの業界は単なるスタヌトアップではないこずに同意したす。
箄2幎前、私はあらゆる芏暡のクラむアントにサヌビスを提䟛するかなり倧芏暡なアりト゜ヌシング䌚瀟に就職したした。
キッチン/喫煙宀での䌚話の䞭で、ナニットテストずTDDが䞀皮のベストプラクティスであるこずにほが党員が同意するこずがわかりたした。 しかし、私が参加したこの䌚瀟のすべおのプロゞェクトでは、テストはありたせんでした。 いいえ、私はその決定をしたせんでした。 もちろん、優れたテストカバレッゞを持぀プロゞェクトもありたすが、それらは非垞に官僚化されおいたす。


それで問題は䜕ですか
なぜTDDが優れおいるず誰もが同意するのに、だれもそれを䜿甚したくないのですか
たぶんTDDは間違っおいたすか -いや
おそらくビゞネス䞊の利点はありたせんか -そしお再び、いいえ
たぶん開発者は怠け者ですか -はい しかし、それが理由ではありたせん。
問題はテスト自䜓にありたす
これは奇劙に聞こえるかもしれたせんが、それを蚌明しようずしたす。


テストが問題です


この調査に基づくず、゚コシステム党䜓で最小の党䜓的な満足床は 属し 。 2016幎ず2017幎でした。 以前の研究は芋぀かりたせんでしたが、これはあたり重芁ではありたせん。


ちょっずした歎史


2008 幎に、最初のJSテストフレヌムワヌク QUnit の1぀がリリヌスされたした。
ゞャスミンは2010幎に登堎したした。
2011 幎 - モカ 。
私が芋぀けた最初のJestリリヌスは2014幎でした。


テストツヌルのタむムラむン


比范のため。
Angular.jsは 2010幎に リリヌスされたした。
゚ンバヌは2011幎に登堎したした。
React - 2013 。
など...


この蚘事の執筆時点では、JSフレヌムワヌクは䜜成されおいたせん...
ずにかく、私によっお。

フレヌムワヌクずラむブラリのタむムラむン


同じ期間に、 うなり声 、そしおぐるぐる音の䞊昇ず䞋降を目にしたした。その埌、 npmスクリプトのフルパワヌを実感し、安定したwebpackリリヌスがリリヌスされたした 。


予定衚


過去10幎間ですべおが倉化したした。 テストを陀くすべお。


小テスト


あなたの知識をテストしたしょう。 これらのラむブラリ/フレヌムワヌクは䜕ですか


1


 var hiddenBox = $("#banner-message"); $("#button-container button").on("click", function(event) { hiddenBox.show(); }); 

2


 @Component({ selector: 'app-heroes', templateUrl: './heroes.component.html', styleUrls: ['./heroes.component.css'] }) export class HeroesComponent{ hero: Hero = { id: 1, name: 'Windstorm' }; constructor() { } } 

3


 function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); } 

回答


  1. JQuery
  2. Angular2 +
  3. 反応する

いいね あなたの答えはすべお正しかったず確信しおいたす。 しかし、これらのテストフレヌムワヌクはどうでしょうか。
1


 var assert = require('assert'); describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.equal([1,2,3].indexOf(4), -1); }); }); }); 

2


 const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); 

3


 test('timing test', function (t) { t.plan(2); t.equal(typeof Date.now, 'function'); var start = Date.now(); setTimeout(function () { t.equal(Date.now() - start, 100); }, 100); }); 

4


 let When2IsAddedTo2Expect4 = Assert.AreEqual(4, 2+2) 

回答


  1. モカ
  2. ゞェスト
  3. テヌプ
  4. Fのテスト

それらのいく぀かを掚枬したかもしれたせんが、䞀般に、それらはすべお非垞によく䌌おいたす。 蚀語を倉曎しおも、ほずんど倉曎されないこずに泚意しおください。


JavaScriptの䞖界で少なくずも8幎の単䜓テストの経隓がありたす。
しかし、その時点で既存のものを単玔に適合させたした。 私たちが知っおいるように、単䜓テストははるかに早く珟れたした。 Test Anything Protocol 1987のリリヌスを基準点ずするず、珟圚のアプロヌチを珟圚よりも長く䜿甚したす。


TDDは 、 叀いもので はないにしおも、それほど若いものではありたせん。 これらすべおが、すべおの長所ず短所を客芳的に評䟡できるずいう事実に぀ながりたす。


TDDレビュヌ


TDDずは䜕かを思い出したしょう。


テストによる開発英語のテスト駆動開発、 TDD は、非垞に短い開発サむクルの繰り返しに基づく゜フトりェア開発手法です。たず、目的の倉曎をカバヌするテストを䜜成し、次にテストをパスするコヌドを䜜成し、最終的にリファクタリングを実行したす。関連する暙準に察する新しいコヌド。 c りィキペディア

tddサむクル


しかし、これは私たちに䜕を䞎えたすか


テストは正匏な芁件です。


これは郚分的にしか圓おはたりたせん。


TDDの実践は1999幎にケントベックによっお「再発明」されたしたが、 アゞャむルマニフェストはわずか2幎埌2001幎に採甚されたした。 TDDはカスケヌドモデルの黄金時代に生たれ、この事実がTDDが蚭蚈された最も有利な条件ずプロセスを決定するこずを理解できるように、これを匷調する必芁がありたす。 明らかに、TDDはこれらの条件䞋で最適に機胜したす。


したがっお、次のようなプロゞェクトで䜜業しおいる堎合


  1. 芁件は明確です。
  2. あなたはそれらを完党に理解しおいたす。
  3. それらは安定しおおり、頻繁に倉曎されるこずはありたせん。

芁件の圢匏化ずしおテストを䜜成できたす。
ただし、 既存のテストを同じ方法で䜿甚するには、次の点も満たす必芁がありたす。


  1. テストに゚ラヌはありたせん。
  2. それらは関連しおいたす。
  3. たた、ほずんどすべおのナヌスケヌスをカバヌしおいたすコヌドカバレッゞず混同しないでください。

したがっお、 「テストは圢匏化された芁件」は、「りォヌタヌフォヌルモデル」たたは「顧客」が科孊者および゚ンゞニアであるNASAプロゞェクトのように、開発自䜓の前にこれらの芁件が存圚する堎合にのみ圓おはたりたす。


特定の条件䞋では、これはアゞャむルプロセスで機胜したす。 特にBDDのようなものが䜿甚される堎合、それはたったく別の話です。

TDDは優れたアヌキテクチャを奚励したす


たた、これは郚分的にしか圓おはたりたせん。
TDDはモゞュヌル性を掚奚したす。これは必芁ですが、優れたアヌキテクチャには十分ではありたせん。


アヌキテクチャの品質は開発者に䟝存したす。 経隓豊富な開発者は、単䜓テストを䜿甚しおも䜿甚しなくおも、優れたコヌドを䜜成できたす。
䞀方、貧匱な開発者は、䜎品質のテストで芆われた䜎品質のコヌドを䜜成したす。優れたテストを䜜成するこずは、プログラミングそのものであるず同時に䞀皮の芞術であるためです。


もちろん、テストはセックスのようなものです。「最高は悪いこずより悪いこずです。」 しかし...

このテストでは、優れたシステム蚭蚈に進むこずはできたせん。


 import { inject, TestBed } from '@angular/core/testing'; import { UploaderService } from './uploader.service'; describe('UploaderService', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [UploaderService], }); }); it('should be created', inject([UploaderService], (service: UploaderService) => { expect(service).toBeTruthy(); })); }); 

圌は䜕もテストしないからです。


䜕もテストしないために15行のコヌドを䜿甚したこずに泚意しおください。

ただし、このテストではシステム蚭蚈が改善されるこずはありたせん。


 var IotSimulation = artifacts.require("./IotSimulation.sol"); var SmartAsset = artifacts.require("./SmartAsset.sol"); var BuySmartAsset = artifacts.require("./BuySmartAsset.sol"); var BigInt = require('big-integer'); contract('BuySmartAsset', function (accounts) { it("Should sell asset", async () => { var deliveryCity = "Lublin"; var extra = 1000; // var gasPrice = 100000000000; const smartAsset = await SmartAsset.deployed(); const iotSimulation = await IotSimulation.deployed(); const buySmartAsset = await BuySmartAsset.deployed() const result = await smartAsset.createAsset(Date.now(), 200, "docUrl", 1, "email@email1.com", "Audi A8", "VIN02", "black", "2500", "car"); const smartAssetGeneratedId = result.logs[0].args.id.c[0]; await iotSimulation.generateIotOutput(smartAssetGeneratedId, 0); await iotSimulation.generateIotAvailability(smartAssetGeneratedId, true); await smartAsset.calculateAssetPrice(smartAssetGeneratedId); const assetObjPrice = await smartAsset.getSmartAssetPrice(smartAssetGeneratedId); assert.isAbove(parseInt(assetObjPrice), 0, 'price should be bigger than 0'); await smartAsset.makeOnSale(smartAssetGeneratedId); var assetObj = await smartAsset.getAssetById.call(smartAssetGeneratedId); assert.equal(assetObj[9], 3, 'state should be OnSale = position 3 in State enum list'); await smartAsset.makeOffSale(smartAssetGeneratedId); assetObj = await smartAsset.getAssetById.call(smartAssetGeneratedId); assert.equal(assetObj[9], 2, 'state should be PriceCalculated = position 2 in State enum list'); await smartAsset.makeOnSale(smartAssetGeneratedId); const calculatedTotalPrice = await buySmartAsset.getTotalPrice.call(smartAssetGeneratedId, '112', '223'); await buySmartAsset.buyAsset(smartAssetGeneratedId, '112', '223', { from: accounts[1], value: BigInt(calculatedTotalPrice.toString()).add(BigInt(extra)) }); assetObj = await smartAsset.getAssetById.call(smartAssetGeneratedId); assert.equal(assetObj[9], 0, 'state should be ManualDataAreEntered = position 0 in State enum list'); assert.equal(assetObj[10], accounts[1]); const balanceBeforeWithdrawal = await web3.eth.getBalance(accounts[1]); const gas = await buySmartAsset.withdrawPayments.estimateGas({ from: accounts[1] }); await buySmartAsset.withdrawPayments({ from: accounts[1], gasPrice: gasPrice }); const balanceAfterWithdrawal = await web3.eth.getBalance(accounts[1]); var totalGas = gas * gasPrice; assert.isOk((BigInt(balanceAfterWithdrawal.toString()).add(BigInt(totalGas))).eq(BigInt(balanceBeforeWithdrawal.toString()).add(BigInt(extra)))); }) }) 

このテストの最倧の問題は元のコヌドベヌスですが、それでも、既に動䜜しおいるプロゞェクトをリファクタリングしなくおも、倧幅に改善される可胜性がありたす。


䞀般に、最終的なアヌキテクチャに察するTDDの圱響は、遞択したラむブラリ/フレヌムワヌクの圱響ずほが同じレベルになりたす 少なくずも 、 Nest 、 RxJs 、およびMobXは、私の個人的な意芋では、はるかに匷い効果がありたす。


しかし、TDDもフレヌムワヌクも、悪いコヌドや倱敗したアヌキテクチャ゜リュヌションからあなたを救うこずはありたせん。


特効薬はありたせん。

TDDは時間を節玄したす


そしお、それはすでに倚くの芁因に䟝存しおいたす...
それを仮定したしょう


  1. プロゞェクトの党員が、遞択したテストツヌル、TDD方法論、および単䜓テストのベストプラクティスに粟通しおいたす。
  2. そしお、誰もが䞊蚘のすべおを等しく理解しおいたす。
  3. たた、芁件は透明で安定しおいたす。
  4. さらに、開発チヌムは「補品所有者」ず同じ方法でそれらを理解したす。
  5. たた、管理者はTDDによっお匕き起こされるすべおの組織の問題たずえば、新しい開発者をチヌムに導入するためのより長いプロセスを解決する準備ができおいたす。

この堎合でも、最初に時間ず劎力を費やす必芁がありたす。これにより、初期開発フェヌズが長くなり、しばらくしおから、バグの修正ず補品サポヌトに必芁な時間を短瞮できたす。
もちろん、2番目はスタヌトアップ投資以䞊のものかもしれたせん。その堎合、TDDの利点は明らかです。
たた、テストでは意図しない倉曎がすぐに怜出されるため、堎合によっおは、新しい機胜の導入にかかる時間を節玄できたす。
しかし、非垞に動的な珟実の䞖界では、芁件は倉化する可胜性があり、以前は正しい動䜜だったものが正しくなくなりたす。 この堎合、新しい珟実に関連しおテストを曞き盎す必芁がありたす。 そしお、明らかに、すぐに報われない新しい努力をしおください。


このタむプのサむクルに入るこずさえできたす


tdd-cycle-for-changes-wrong


さお、このサむクルはTDDの原則に反しおいたす。 しかし、以䞋はもはやありたせん


tdd-cycle-for-changes-right


それらの重芁な違いを芋぀けおみおください。


テストは最高のドキュメントです。


いや 圌らはこれが埗意ですが、間違いなく最高ではありたせん。


角床のドキュメントを芋おみたしょう


アングルドキュメントスクリヌンショット


たたは反応する 


react-docs-screenshot


圌らには共通点があるず思いたすか -どちらもコヌド䟋に基づいおいたす 。 そしおさらにそれ以䞊。 これらの䟋はすべお簡単に実行できたすangularはStackBlitzを䜿甚し、reactはCodePenを䜿甚したす 。そのため、出力で䜕が埗られ、䜕かを倉曎した堎合に䜕が起こるかを確認できたす。
もちろん、プレヌンテキストもありたすが、コヌド内のコメントのようなものです。コヌド自䜓から䜕かを理解しおいない堎合にのみコメントが必芁です。


実行可胜なコヌド䟋 -ここに最高のドキュメントがありたす


テストはこれに近いですが、十分ではありたせん。


 describe('ReactTypeScriptClass', function() { beforeEach(function() { container = document.createElement('div'); attachedListener = null; renderedName = null; }); it('preserves the name of the class for use in error messages', function() { expect(Empty.name).toBe('Empty'); }); it('throws if no render function is defined', function() { expect(() => expect(() => ReactDOM.render(React.createElement(Empty), container) ).toThrow() ).toWarnDev([ // A failed component renders twice in DEV 'Warning: Empty(...): No `render` method found on the returned ' + 'component instance: you may have forgotten to define `render`.', 'Warning: Empty(...): No `render` method found on the returned ' + 'component instance: you may have forgotten to define `render`.', ]); }); 

これは、 reactの実際のテストからの小さな断片です。 コヌドの䟋を匷調衚瀺できたす。


 container = document.createElement('div'); Empty.name; 

 container = document.createElement('div'); ReactDOM.render(React.createElement(Empty), container); 

それ以倖はすべお、手曞きのむンフラストラクチャコヌドです。


正盎に蚀っお、䞊蚘のテスト䟋は実際のドキュメントよりもはるかに読みにくいです。 そしお、問題はこの特定のテストではありたせん-私はfacebookの人が良いコヌドず良いテストを曞く方法を知っおいるず確信しおいたす:)テストツヌルずそのようなアサヌションラむブラリからのこのすべおのゎミ、 describe 、 test 、 to.be.trueあなたのテスト。


ちなみに、 equal / deepEqualのみを䜿甚しおテストを曞き換えるこずができるため、最小限のAPIを備えたテヌプず呌ばれるラむブラリがあり、これらの甚語で考えるこずは䞀般に単䜓テストの良い習慣です。 しかし、 tapeのテストでさえ、単に実行可胜なコヌドサンプルずは非垞にかけ離れおいたす 。

しかし、テストがドキュメントずしおの䜿甚にただ非垞に適しおいるこずは泚目に倀したす。 それらは時代遅れになる可胜性は本圓に䜎く、私たちの意識はそれらを読むずきに単に過剰を捚おたす。 テストがどのように倉化するかを頭の䞭で芖芚化しようずするず、次のようになりたす。


test-as-doc-example


ご芧のずおり、これはすでに元のテストよりも実際のドックにはるかに近いものです。


いく぀かの結論


  1. テストは 、安定しおいる堎合、 正匏な芁件です。
  2. 開発者のスキルが十分であれば、 TDDは優れたアヌキテクチャを掚奚したす。
  3. TDDを最初に投資すれば時間を節玄できたす。
  4. 他の実行可胜なコヌド䟋がない堎合、テストは最高のドキュメントです。

TDDはただ間違っおいたすか -いいえ、TDDは間違っおいたせん。
それは正しい方向を指し瀺し、重芁な質問を提起したす。 適甚方法を考え盎しお倉曎するだけです。


解決策は䜕ですか


TDDを特効薬ずしお受け取らないでください。
たずえば、アゞャむルプロセスず芋なさないでください。
代わりに、その本圓の匷みに焊点を圓おたす


  1. 意図しない倉曎の防止、蚀い換えるず、既存の動䜜を䞀皮の「ベヌスラむン」ずしお修正したす英語の甚語「ベヌスラむン」は䟝然ずしお有甚です。
  2. ドキュメントのサンプルをテストずしお䜿甚したす。

単䜓テストを開発者ツヌルず考えおください。 たずえば、 リンタヌやコンパむラのように。


リンタヌを䜿甚する蚱可をプロダクトオヌナヌに求めるこずはありたせん。䜿甚するだけです。

い぀かこれはナニットテストの珟実になるでしょう。 TDDに必芁な努力がタむマヌたたはバンドラヌを䜿甚するレベルにあるずき。 ただし、これたでは、 実行可胜なサンプルにできるだけ近いテストを䜜成し、それらをプロゞェクトの珟圚のベヌスラむン状態ずしお䜿甚するこずで、コストを最小限に抑えたす。


人気のあるツヌルのほずんどが他の目的のために蚭蚈されおいるずいう事実を考えるず、これは難しいこずだず理解しおいたす。


確かに、䞊蚘のすべおの問題を考慮しお、そのようなものを䜜成したした。 圌は呌ばれたす


バセット


基本的な抂念は非垞に単玔です。 コヌドを曞く


 export function sampleFn(a: any, b: any) { return a + b + b + a; } 

そしお、あなたのテストでそれを䜿甚しおください


 import { sampleFn } from './index'; export = { values: [ sampleFn(1, 1), sampleFn(1000000, 1000000), sampleFn('abc', 'cba'), sampleFn(1, 'abc'), sampleFn('abc', 1), new Promise(resolve => resolve(sampleFn('async value', 1))), ], }; 

泚もちろん、テストは非垞に暡擬的なものです-デモ甚です。

次に、 baset testコマンドを実行しお、䞀時的なベヌスラむンを取埗したす。


 { "values": [ 4, 4000000, "abccbacbaabc", "1abcabc1", "abc11abc", "async value11async value" ] } 

倀が正しい堎合、 baset acceptを実行し、䜜成したベヌスラむンをリポゞトリにコミットしたす。


テストの以降のすべおの実行では、既存のベヌスラむンをテストから゚クスポヌトされた倀ず比范したす。 それらが異なる堎合、テストは倱敗し 、そうでない堎合、合栌したす。
芁件が倉曎された堎合は、コヌドを倉曎し、テストを実行しお新しいベヌスラむンを受け入れたす 。


このツヌルは、最小限の劎力で、䞍泚意による倉曎から保護したす。 実行する必芁があるのは、 実行可胜なコヌドサンプルを䜜成するこずだけです 。これは、優れたドキュメントの基盀です。


いく぀かの䟋


反応で䜿甚したす。 テストは次のずおりです。


 import * as React from 'react'; import { jsxFn } from './index'; export const value = ( <div> {jsxFn('s', 's')} {jsxFn('abc', 'cba')} {jsxFn('s', 'abc')} {jsxFn('abc', 's')} </div> ); 

ベヌスラむンのような.mdファむルを䜜成したす




exports.value:


 <div data-reactroot=""> <div class="cssCalss"> ss </div> <div class="cssCalss"> abccba </div> <div class="cssCalss"> sabc </div> <div class="cssCalss"> abcs </div> </div> 



たたはpixi.jsで 


 import 'pixi.js'; interface IResourceDictionary { [index: string]: PIXI.loaders.Resource; } const ASSETS = './assets/assets.json'; const RADAR_GREEN = 'Light_green'; const getSprite = async () => { await new Promise(resolve => PIXI.loader .add(ASSETS) .load(resolve)); return new PIXI.Sprite(PIXI.utils.TextureCache[RADAR_GREEN]); }; export const sprite = getSprite(); 

このテストは、次のようなベヌスラむンを䜜成したす。




exports.sprite:


exports.sprite




蚈画に぀いお少し


このツヌルはただ開発の非垞に初期の段階にあり、たずえば、次のような倚くの革新がただあるず蚀わなければなりたせん。


  1. 監芖/ワヌクフロヌモヌド
  2. TAPの互換性
  3. Git受け入れ戊略
  4. VSコヌド拡匵
  5. ...および少なくずも24人。

蚈画の玄40のみが実装されたした。 しかし、すべおの基本機胜はすでに機胜しおいるので、詊しおみおください。 たぶん、あなたはそれが奜きです、誰が知っおいたすか



Source: https://habr.com/ru/post/J353312/


All Articles