search
LoginSignup
3
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

レガシーコード改善ガイドの「インターフェースの抽出」をObjective-Cで行うには

以下のクラスをテストしたいとする。

PaydayTransaction.h
@interface PaydayTransaction : Transaction

- (id)initWithDb:(PayrollDatabase*)db withLog:(TransactionLog*)log;
- (void)run;

@end

普通にテストを書くとこうなる。

PaydayTransactionTests.h
@interface PaydayTransactionTests : SenTestCase
{
    PayrollDatabase* _db;
    TransactionLog* _log;
}

@end
PaydayTransactionTests.m
@implementation ExtractInterfaceTests

- (void)setUp
{
    [super setUp];

    // Set-up code here.
    _db = [[PayrollDatabase alloc] init];
    _log = [[TransactionLog alloc] init];
}

- (void)testPayday
{
    PaydayTransaction* t = [[PaydayTransaction alloc] initWithDb:_db withLog:_log];
    [t run];
    STAssertEquals(90, _db.stock, @"_db.stock should be 90");
}

@end

このテストはPaydayTransactionクラスを調べるためのものだが、テストの中でPayrollDatabaseクラスとTransactionLogクラスに依存している。PaydayTransactionクラスの挙動に焦点を絞るために、TransactionLogクラスへの依存を排除したテストを書きたいとする。

つまり、以下のようなテストを書きたい。

PaydayTransactionTests.h
@interface ExtractInterfaceTests : SenTestCase
{
    PayrollDatabase* _db;
}

@end
PaydayTransactionTests.m

@implementation ExtractInterfaceTests

- (void)setUp
{
    [super setUp];

    // Set-up code here.
    _db = [[PayrollDatabase alloc] init];
}

- (void)testPayday
{
    FakeTransactionLog* aLog = [[FakeTransactionLog alloc] init];
    PaydayTransaction* t = [[PaydayTransaction alloc] initWithDb:_db withLog:aLog];
    [t run];
    STAssertEquals(90, _db.stock, @"_db.stock should be 90");
}

@end

Objective-Cはコンパイラが型チェックを行わないので、このままでもコンパイルは通るが、メソッドのシグナチャを合わせることにする。

まずTransactionLogクラスのメソッドを確認する。

TransactionLog.h
@interface TransactionLog : NSObject

- (void)saveTransaction:(TransactionLog*)transaction;
- (void)recordErrorWithCode:(int)code;

@end

次に、以下のようなTransactionRecorderプロトコルおよびクラスをつくる。

TransactionRecorder.h
@protocol TransactionRecorder <NSObject>

- (void)saveTransaction:(TransactionRecorder*)transaction;
- (void)recordErrorWithCode:(int)code;

@end

@interface TransactionRecorder : NSObject <TransactionRecorder>

@end
TransactionRecorder.m
@implementation TransactionRecorder

- (void)saveTransaction:(TransactionRecorder*)transaction
{

}

- (void)recordErrorWithCode:(int)code;
{

}

@end

そして、TransactionLogクラスとFakeTransactionLogクラスにはTransactionRecorderプロトコルを実装する。

TransactionLog.h
@interface TransactionLog : NSObject <TransactionRecorder>

@end
FakeTransactionLog.h
@interface FakeTransactionLog : NSObject <TransactionRecorder>

@end

そして、PaydayTransactionクラスからはTransactionRecorderクラスを参照するようにする。

PaydayTransaction.h
@interface PaydayTransaction : Transaction

- (id)initWithDb:(PayrollDatabase*)db withLog:(TransactionRecorder*)log;
- (void)run;

@end

これでいいのかな?ちょっと不安。


ブログやってます:PAPA-tronix !

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3
Help us understand the problem. What are the problem?