Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

入力時にバリデーションを行い、単体テストを書く #7

Open
ginrou opened this issue Jun 1, 2015 · 3 comments

Comments

Projects
None yet
1 participant
@ginrou
Copy link
Contributor

commented Jun 1, 2015

TODOアプリを作ってみようシリーズの最終回の演習課題です。

内容

TODO入力時のバリデーションと単体テストを取り扱います。

todo7
↑バリデーションの様子

todo8
↑テスト実行の様子. この例では失敗してます。

目的

  • 入力値のバリデーションを行えるようにする
  • UIAlertControllerを表示する
  • 単体テストが書けるようになる

スタート地点

前回( #6 )のゴール地点であるブランチlocal-notification からスタートしてください。

ゴール地点

ブランチ unit-testを見ると解答例が書いてあります。

教材

アプリの仕様

  • TODOを入力する時に以下のバリデーション(入力値検査)を行うようにしてください
    • TODOの本文がきちんと含まれていること (ゼロ文字や空白のみはダメ)
    • 締め切り時間が現在より先に設定されていること (過去の締め切りはダメ)
  • 入力値が不正な場合は、渓谷するアラートを表示する
  • 入力値検査に関する単体テストを書く

実装の方針

TODO追加時にバリデーションを行い、不十分な場合はアラートを表示する 4a49faf

まず、入力されたTODOが仕様を満たすかどうかをチェックするメソッドを作ります。
仕様を満たす場合は YES を、満たさない場合は NO を返すようにします。

そしてTODOが正しくない場合はアラートを表示します。
アラートの表示にはUIAlertControllerを用います。使い方は差分のコードを見てください。
リファレンスは UIAlertController Class Reference になります。

このUIAlertControllerはiOS8でクラス名が変更になったクラスで、以前はUIAlertViewを利用していました。

単体テストを追加する b4eb18b

次に単体テストを追加していきます。テストフレームワークであるXCTestがプロジェクト作成時に導入されているのでそれを利用します。
今回テストを行いたい対象はAddTodoViewControllerなのでAddTodoViewController.mのターゲットにTodoTestsを追加します。

2015-06-01 3 57 40 pm

次に新規テストファイルを追加します。NewFileからテンプレートは"Test Case Class"を選択し、subclass of はXCTestCaseを選択します。
ファイル名は特に制約はありませんがAddTodoViewControllerTestsなどにすると分かりやすいです。

テストファイルが追加できたらテストターゲットのヘッダファイルをimportしてテストを記述します。
XCTestによるテストの記述方法は教材を参照してください。
テストには、成功するパターンや失敗するパターン、異常な入力などの様々なパターンを網羅するとより安心して開発に望むことができます。
ちなみに 4a49faf では以下のケースに対するケアが漏れていて、テストを実行すると失敗となります。

  • todoの本文が空白文字のみ
  • 締め切り日時にnilを渡したケース
@ginrou

This comment has been minimized.

Copy link
Contributor Author

commented Jun 4, 2015

テストの実行は

  • メニューのProduct → Run
  • ⌘ + U

で実行できます。

@ginrou

This comment has been minimized.

Copy link
Contributor Author

commented Jun 4, 2015

以下のテストケースを実装してみてください

    // 順正常系 : NOが返るパターン
    // 1. titleが空文字列の場合
    // 2. titleがキーとして存在しない場合
    // 3. titleが空白のみの場合
    // 4. dateが昔のパターン
    // 5. dateがキーとして存在しない場合パターン
    // 6. 引数にnilを渡したパターン
    // 7. dateの型がNSStringの場合
    // 8. 余分なkey-valueペアがある場合 : 成功するパターン
@ginrou

This comment has been minimized.

Copy link
Contributor Author

commented Jun 4, 2015

テストケース解答例

    // 正常系
    todo = @{@"title": title, @"date": date};

    XCTAssertTrue([vc isValidToDo:todo]);

    // 順正常系 : NOが返るパターン
    // 1. titleが空文字列の場合
    todo = @{@"title": @"", @"date": date};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 2. titleがキーとして存在しない場合
    todo = @{@"date": date};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 3. titleが空白のみの場合
    todo = @{@"title": @"     ", @"date": date};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 4. dateが昔のパターン
    todo = @{@"title": title, @"date": [NSDate dateWithTimeIntervalSinceNow:-100]};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 5. dateがキーとして存在しない場合パターン
    todo = @{@"title": title};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 6. 引数にnilを渡したパターン
    XCTAssertFalse([vc isValidToDo:nil]);

    // 7. dateの型がNSStringの場合
    todo = @{@"title": title, @"date": @"hogehoge"};
    XCTAssertFalse([vc isValidToDo:todo]);

    // 8. 余分なkey-valueペアがある場合 : 成功するパターン
    todo = @{@"title": title, @"date": date, @"hoge": @(10)};
    XCTAssertTrue([vc isValidToDo:todo]);

メソッドisValidTodo: も以下のようになります

- (BOOL)isValidToDo:(NSDictionary *)todo
{
    NSString *title = todo[@"title"];
    NSDate *date = todo[@"date"];

    NSString *trimedTitle = [title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if (date == nil) return NO;
    if ([date isKindOfClass:[NSDate class]] == NO) return NO;

    if (trimedTitle.length == 0) return NO;
    if ([date timeIntervalSinceNow] < 0.0) return NO;

    return YES;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.