応用TDD:ReactNative実戦編
40258 ワード
いわゆるTDD
[テストドライバ開発]バー
ソフトウェア開発方法論の1つとして、開発自体は「テスト」が主導している.製品の機能を実現するために、まずテストコードを作成し、その機能が正常に動作しているかどうかを検証する.
TDD開発段階
なぜTDDを使うのですか?
従来の開発方式を採用すれば、消費者の需要は最初から明確ではない可能性があるため、最初から完璧な設計を行うことは難しい.また、再設計とコード書き換えを繰り返すと、製品の品質が低下します.小さな機能変更でも、すべての部分を再テストする必要があり、テストコストが増加します.
TDDはテストコードと製品コードを機能別に記述するため,低依存性と低依存性のモジュール化方式で開発する.これにより、再設計、デバッグ時間が短縮され、さらなる実装が容易になります.(特に既存のコードへの影響を最小限に抑えることができる)
リポジトリのインストールと紹介
JEST
Facebookで作成したJavaScriptテストライブラリです.react-native-cliを使用してプロジェクトを構成する場合、dev依存項目に含まれています.
Enzyme
Airbe&Bによって作成されたReact構成部品テストライブラリです.酵素、酵素-アダプタ-反応、反応-domを同時に設定します.
Detox
ユーザの観点からEnd to Endのライブラリをテストします.Android/iosはサポートされていますが、まずiosでテストしただけです.リンゴソース、デトックス-cli、デトックス、jest-marchを同時に設定します.
ToDoListテストコードの作成
構成部品をレンダリングしpropsを確認する
以下の簡単なToDoリストのテストコードを作成します!
まず、アプリケーションを初めて実行するときに、画面タイトルに使用される「TODOTDD」コンテンツが以下のテキストコンポーネントに含まれているかどうか、およびAddToDoおよびToDoListが存在するかどうかを記述することができる.
describe('App', () => {
const wrapper = shallow(<App></App>);
test('snapshot test', () => {
expect(wrapper).toMatchSnapshot();
});
it('is Text visible?', () => {
expect(wrapper.find('Text').contains('ToDo TDD')).toBe(true);
});
it('is AddToDO visible?', () => {
expect(wrapper.find('AddToDo')).toHaveLength(1);
});
it('is ToDoList visibla?', () => {
expect(wrapper.find('ToDoList')).toHaveLength(1);
});
});
AddToDoコンポーネントはTextInputとボタンで構成されており、ボタンをクリックするとTextInput内部のOnAdded関数が呼び出されます.内部に対応するコンポーネントがあるかどうかを確認する操作は、上記のコードと類似しているため、関数呼び出し関連部分の作成方法は次のとおりです.テストを行う前に、AddToDoをレンダリングし、TextInputコンテンツを作成し、ボタンを押します.次にitでOnAdded関数が呼び出されたかどうか、テキストコンテンツがあるかどうかを確認します.describe('AddToDo Interaction', () => {
let wrapper;
let props;
const text = 'Add To Do Item';
beforeEach(() => {
props = {
onAdded: jest.fn(),
};
wrapper = shallow(<AddToDo {...props}></AddToDo>);
wrapper.find('TextInput').simulate('changeText', text);
wrapper.find('Button').prop('onPress')();
});
it('should call the onAdded callback with input text', () => {
expect(props.onAdded).toHaveBeenCalledTimes(1);
expect(props.onAdded).toHaveBeenCalledWith(text);
});
});
ToDonderItemのテストコードを記述するのも似ています.デフォルトでは、テキスト、Buttonの内部位置が適切かどうか、初期スタイルはどうか、propsが特定のデータを入力した場合、どのような異なるスタイルがあるかを決定します.その後、各ボタンのクリックに伴い、対応する関数が正しく呼び出されたか否かを決定することができる.// component rendering
describe('rendering', () => {
let warpper;
let props;
beforeEach(() => {
props = {
item: {},
};
wrapper = shallow(<ToDoRenderItem {...props}></ToDoRenderItem>);
});
it('should render a Text', () => {
expect(wrapper.find('Text')).toHaveLength(1);
});
it('should render two buttons', () => {
expect(wrapper.find('Button')).toHaveLength(2);
});
describe('Uncompleted', () => {
it('should have the default style', () => {
expect(wrapper.prop('style')).toBe(styles.default);
});
});
describe('Completed', () => {
beforeEach(() => {
props.item.completed = true;
wrapper = shallow(<ToDoRenderItem {...props}></ToDoRenderItem>);
});
it('should have the completed style', () => {
expect(wrapper.prop('style')).toBe(styles.completed);
});
});
});
// interaction
describe('interaction', () => {
let wrapper;
let props;
beforeEach(() => {
props = {
item: {text: 'first ToDo', completed: false},
index: 0,
onCompleted: jest.fn(),
onDeleted: jest.fn(),
};
wrapper = shallow(<ToDoRenderItem {...props}></ToDoRenderItem>);
});
it('Complete feature', () => {
wrapper.find('Button').at(0).prop('onPress')();
expect(props.onCompleted).toHaveBeenCalledTimes(1);
expect(props.onCompleted).toHaveBeenCalledWith(props.index);
});
it('Delete feature', () => {
wrapper.find('Button').at(1).prop('onPress')();
expect(props.onDeleted).toHaveBeenCalledTimes(1);
expect(props.onDeleted).toHaveBeenCalledWith(props.index);
});
});
ワークショップで議論している間に、これらのコードをすべて1つのファイルに書くべきかどうかを聞かれ、sangtestコマンドを実行すると、フォルダ内のすべてのテストコードファイルが実行され、確認され、コンポーネントと機能に応じて適切に区分すればよい.ファイルを初めて実行すると、すべてのテストに失敗が表示されます.これは前述のREDステージです!テストコードを通過したGREENフェーズが実行できるようになりました.(BLUEフェーズが以降のテストコードに関係のないフェーズであることを忘れないでください)作成したコードがすべての対応するテストコードを通過できる場合、糸テストコマンドで実行すると、以下の結果が表示されます.
E 2 Eの動作をDetoxでチェック
前のように構成部品のレンダリングまたは内部データを表示できますが、ユーザーが実際にサービスを使用するすべてのスキームが正常に動作するようにするにはどうすればいいですか?DetoxのEnd To Endテスト機能を使用して、ToDonderItemを直接追加/完了または削除するプロセスが正常であることを確認します.
追加と完了
describe('Interaction Test', () => {
beforeAll(async () => { // 처음에 앱을 실행하고
await device.launchApp();
});
beforeEach(async () => { // 매 테스트마다 리로드를 통해 혹시 모를 영향을 끼칠 요소들을 방지하자
await device.reloadReactNative();
});
it('Completing ToDo Item should work!', async () => {
const text = '입력 완료 여부 체크';
await element(by.id('textInput')).tap();
await element(by.id('textInput')).typeText(text);
await element(by.id('addButton')).tap();
await element(by.id('completeButton')).multiTap(1);
await expect(
element(
// toDoList라는 아이템 내에 '입력 완료 여부 체크'라는 내용을
// 가진 텍스트가 있는지 확인하고,
// 그 아이디가 현재 testId로 'completed'를 가지고있는지 확인한다.
by.id('completed').and(by.text(text)).withAncestor(by.id('toDoList')),
),
).toBeVisible();
});
it('Deleting ToDo Item should work!', async () => {
const text = '입력 삭제 여부 체크';
await element(by.id('textInput')).tap();
await element(by.id('textInput')).typeText(text);
await element(by.id('addButton')).tap();
await element(by.id('deleteButton')).multiTap(1);
await expect(
element(by.text(text).withAncestor(by.id('toDoList'))),
).not.toBeVisible(); // not toBeVisible
});
});
deuto build-ciosで構築し、deuto test-c iosでテストし、以下の結果を確認できます.テストコマンドを実行するときは、以下のように、実際のアプリケーションを実行しながら、ユーザーがテキストを入力したり、ボタンをクリックしたりして、目でシーンの実行状況をテストすることができます.実行中に端末をチェックすると、[OK]文が追加され、テストの実行に伴って正常に実行されたことを示し、テストが成功/失敗したかどうかを詳細に説明します.QA時間を大幅に短縮することができ、個人的にはとても満足しています.
途中でコードを交換した後、再ロードされて自動的にコードに反映されるべきだと思いましたが、ワークショップでは継続していなかったので、いっそ構築内容をキャンセルして確認したところ、正常に行われました.△さらにxcode clean buildのためにコマンドを解放し、再構築したが、そのコマンドは起動しなかった...xcodeで構築されたのではなく、私は何を言っているのだろうか.ダメならデトックス公式文書で言うとおりにしましょう…!
TDDを使う必要はありません。
もちろん、すべてのプロジェクトや他のすべての状況でTDDを使用する必要はありません.TDDを初めて導入する場合、初期コストはTDDを使用しない場合よりも大きくなります(テストコードの作成).また、TDDはエラーを事前に発見させるだけです.エラーの「解決」は最終的に開発者が担当することを忘れてはいけません.また、テストコードを繰り返すだけで、これらのコードを意味なく使用することは、ビジネスプロセスの増加につながるだけです.TDDは、共通の目標を効率的に実現するための「ツール」です.羅、忘れないで、よく使って結局私達の手の中で掌握します
Reference
この問題について(応用TDD:ReactNative実戦編), 我々は、より多くの情報をここで見つけました https://velog.io/@dalbodre_ari/TDD-적용하기-ReactNative-실전편テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol