Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ダックタイピングとidでUserDefaultsをモック化する

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for 417.72KI 417.72KI
September 05, 2019

 ダックタイピングとidでUserDefaultsをモック化する

Avatar for 417.72KI

417.72KI

September 05, 2019
Tweet

More Decks by 417.72KI

Other Decks in Programming

Transcript

  1. struct Me { let name = "Takuhiro Muta" let aka

    = "417.72KI" let twitter = "417_72ki" let qiita = "417_72ki" let gitHub = "417-72KI" let products = [ "BuildConfig.swift", "MockUserDefaults", ] let workAt = [ "Rhizome Inc.": "2014/04~2018/01", "iRidge Inc.": "2018/02~2019/08", "WealthNavi Inc.": "2019/09~", ] } TFMGEFTDSJQUJPO
  2. QSPUPDPMΛט·ͤΔ protocol UserDefaultsProtocol: class { func object(forKey defaultName: String) ->

    Any? func set(_ value: Any?, forKey defaultName: String) func string(forKey defaultName: String) -> String? ɾ ɾ ɾ } extension UserDefaults: UserDefaultsProtocol {}
  3. QSPUPDPMΛט·ͤΔ class MockUserDefaults { private var mockDictionary: [String: Any] =

    [:] } extension MockUserDefaults: UserDefaultsProtocol { func object(forKey defaultName: String) -> Any? { return mockDictionary[defaultName] } func set(_ value: Any?, forKey defaultName: String) { mockDictionary[defaultName] = value } ɾ ɾ ɾ }
  4. QSPUPDPMΛט·ͤΔ protocol UseCase { var userDefaults: UserDefaultsProtocol { get }

    func doSomething() } extension UseCase { func doSomething() { userDefaults.set("bar", forKey: "foo") } } class MixInUseCase: UseCase { let userDefaults: UserDefaultsProtocol = UserDefaults.standard } class TestUseCase: UseCase { let userDefaults: UserDefaultsProtocol = MockUserDefaults() } "QQ 5FTU
  5. TVJUF/BNFΛ࢖͏ protocol UseCase { var userDefaults: UserDefaults { get }

    func doSomething() } extension UseCase { func doSomething() { userDefaults.set("bar", forKey: "foo") } } class MixInUseCase: UseCase { let userDefaults: UserDefaults = .standard } class TestUseCase: UseCase { let userDefaults: UserDefaults = .init(suiteName: "Mock")! } "QQ 5FTU
  6. 0CKFDUJWF$ʹ͓͚Δ μοΫλΠϐϯά @interface Duck: NSObject - (void)walk; - (void)quack; @end

    @implementation Duck - (void)walk { NSLog(@"Duck walking"); } - (void)quack { NSLog(@"Quack!!"); } @end @interface Dog: NSObject - (void)walk; - (void)bark; @end @implementation Dog - (void)walk { NSLog(@"Dog walking"); } - (void)bark { NSLog(@"Bark!!"); } @end void walkAndQuack(id duck) { [duck walk]; [duck quack]; }
  7. 0CKFDUJWF$ʹ͓͚Δ μοΫλΠϐϯά void walkAndQuack(Duck *duck) { [duck walk]; [duck quack];

    } walkAndQuack([Duck new]); walkAndQuack([Dog new]); *ODPNQBUJCMFQPJOUFSUZQFTQBTTJOH%PH  UPQBSBNFUFSPGUZQF%VDL  ܯࠂ͕ग़Δ͚ͩͰϏϧυ͸௨Δ
  8. @protocol UITableViewDataSource<NSObject> @required - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView

    *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; @optional - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; ɾ ɾ ɾ %FMFHBUFͱμοΫλΠϐϯά ࣮૷Λڧ੍͠ͳ͍ϝιου܈
  9. @implementation UITableView ɾ ɾ ɾ - (NSInteger)numberOfSections { if ([self.dataSource

    respondsToSelector:@selector(numberOfSectionsInTableView:)]) { return [self.dataSource numberOfSectionsInTableView:self]; } else { return 1; } } ɾ ɾ ɾ @end %FMFHBUFͱμοΫλΠϐϯά ϝιου͕࣮૷͞Ε͍ͯΔ͔νΣοΫ
  10. %FMFHBUFͱμοΫλΠϐϯά @interface HogeViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, weak)

    IBOutlet UITableView *tableView; @end @implementation HogeViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self; self.tableView.delegate = self; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { ɾɾɾ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ɾɾɾ } @end ϓϩτίϧએݴ σϦήʔτϝιου
  11. %FMFHBUFͱμοΫλΠϐϯά @interface HogeViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, weak)

    IBOutlet UITableView *tableView; @end @implementation HogeViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self; self.tableView.delegate = self; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { ɾɾɾ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ɾɾɾ } @end OVNCFS0G4FDUJPOT*O5BCMF7JFX͕࣮૷͞Ε͍ͯͳ͍ͷͰTFDUJPO͸
  12. %FMFHBUFͱμοΫλΠϐϯά @interface HogeViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (nonatomic, weak)

    IBOutlet UITableView *tableView; @end @implementation HogeViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self; self.tableView.delegate = self; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2 } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { ɾɾɾ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ɾɾɾ } @end OVNCFS0G4FDUJPOT*O5BCMF7JFX͕࣮૷͞ΕͯΛฦ͢Α͏ʹ
  13. @interface HogeViewController : UIViewController @property (nonatomic, weak) IBOutlet UITableView *tableView;

    @end @implementation HogeViewController - (void)viewDidLoad { [super viewDidLoad]; self.tableView.dataSource = self; self.tableView.delegate = self; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2 } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { ɾɾɾ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ɾɾɾ } @end %FMFHBUFͱμοΫλΠϐϯά "TTJHOJOHUPJE6*5BCMF7JFX%BUB4PVSDF@/VMMBCMFGSPN JODPNQBUJCMFUZQF)PHF7JFX$POUSPMMFS DPOTU@@TUSPOH ϓϩτίϧએݴΛফͯ͠Έͨ৔߹ ܯࠂ͕ग़Δ͚ͩͰϏϧυ͸௨Δ Ϋϥογϡ΋ͤͣ5BCMF7JFXͱͯ͠ػೳ͢Δ
  14. NSArray *array = @[ @{@"hoge":@"fuga"}, ]; for (NSObject *obj in

    array) { NSLog([obj objectForKey:@"hoge"]); } JEܕͷԸܙ /PWJTJCMF!JOUFSGBDFGPS/40CKFDUEFDMBSFTUIFTFMFDUPSPCKFDU'PS,FZ
  15. NSArray *array = @[ @{@"hoge":@"fuga"}, ]; for (NSObject *obj in

    array) { NSLog([(NSDictionary *)obj objectForKey:@"hoge"]); } JEܕͷԸܙ Ωϟετ͢Δ͜ͱͰݺͼग़ͤΔΑ͏ʹ
  16. NSArray *array = @[ @{@"hoge":@"fuga"}, ]; for (id obj in

    array) { NSLog([obj objectForKey:@"hoge"]); } JEܕͷԸܙ Ωϟετͤͣʹ/4%JDUJPOBSZͱͯ͠ѻ͏͜ͱ͕Ͱ͖Δ
  17. NSArray *array = @[ @{@"hoge":@"fuga"}, ]; for (NSDictionary *obj in

    array) { NSLog([obj objectForKey:@"hoge"]); } JEܕͷԸܙ /4%JDUJPOBSZͱͯ͠औΓग़ͤΔ ॊೈੑͷߴ͍ίʔσΟϯά͕Մೳʹ
  18. NSArray *array = @[ @{@"hoge":@"fuga"}, @"hogehoge" ]; for (NSDictionary *obj

    in array) { NSLog([obj objectForKey:@"hoge"]); } JEܕͷԸܙ GVHB
  19. NSArray *array = @[ @{@"hoge":@"fuga"}, @"hogehoge" ]; for (NSDictionary *obj

    in array) { NSLog([obj objectForKey:@"hoge"]); } JEܕͷԸܙ VOSFDPHOJ[FETFMFDUPSTFOUUPJOTUBODF
  20. NSArray <NSDictionary <NSString *, id> *> *array = @[ @{@"hoge":@"fuga"},

    @"hogehoge" ]; for (NSDictionary <NSString *, id> *obj in array) { NSLog([obj objectForKey:@"hoge"]); } -JHIUXFJHIU(FOFSJDT 0CKFDUPGUZQF/44USJOH JTOPUDPNQBUJCMFXJUIBSSBZ FMFNFOUUZQF/4%JDUJPOBSZ/44USJOH JE 
  21. ࢀߟจݙ w μοΫɾλΠϐϯά 8JLJQFEJB 
 IUUQTKBXJLJQFEJBPSHXJLJ &&&"'&##& #'&"&&#& # 

    w JEܕͱ͸ಈత݁߹ͷ֓೦
 IUUQTKQSPHSBNFSDPNPCKFDUJWFD  w ·ͭ΋ͱ௚఻ɹϓϩάϥϛϯάͷΦΩςୈճʢʣ
 IUUQTUFDIOJLLFJCQDPKQJUBSUJDMF$0-6./