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

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

417.72KI
September 05, 2019

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

417.72KI

September 05, 2019
Tweet

More Decks by 417.72KI

Other Decks in Programming

Transcript

  1. μοΫλΠϐϯάͱJEͰ
    6TFS%FGBVMUTΛϞοΫԽ͢Δ

    J04%$+BQBOEBZ5SBDL&

    View Slide

  2. 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

    View Slide

  3. "HFOEB
    w ςετͱ6TFS%FGBVMUT
    w μοΫλΠϐϯά
    w JEܕ
    w .PDL6TFS%FGBVMUT

    View Slide

  4. ςετͱ6TFS%FGBVMUT

    View Slide

  5. ςετͱ6TFS%FGBVMUT
    w 6OJU5FTUΛߟ͑Δ্Ͱ6TFS%FGBVMUTͷѻ͍͸ॏཁ
    w 6TFS%FGBVMUTΛ5FTUBCMFʹ͍ͨ͠
    w QSPUPDPMΛט·ͤΔ
    w TVJUF/BNFΛ࢖͏

    View Slide

  6. 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 {}

    View Slide

  7. 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
    }
    ɾ
    ɾ
    ɾ
    }

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. ςετͱ6TFS%FGBVMUT
    w 6TFS%FGBVMUTΛ5FTUBCMFʹ͍ͨ͠
    w QSPUPDPMΛט·ͤΔ
    w طʹ6TFS%FGBVMUTΛϓϩύςΟͱͯ͠࢖༻͍ͯ͠Δ
    ৔߹ɺطଘίʔυʹखΛೖΕΔඞཁ͕͋Δ
    w TVJUF/BNFΛ࢖͏
    w /4)PNF%JSFDUPSZ
    -JCSBSZ1SFGFSFODFT
    TVJUF/BNF
    QMJTU͕࡞੒͞ΕΔ
    w ςετͰӬଓྖҬΛ͍͡Γͨ͘͸ͳ͍

    View Slide

  11. ςετͱ6TFS%FGBVMUT
    w 6TFS%FGBVMUTΛ5FTUBCMFʹ͍ͨ͠
    w QSPUPDPMΛט·ͤΔ
    w TVJUF/BNFΛ࢖͏
    w μοΫλΠϐϯάΛ࢖ͬͨࠇຐज़

    View Slide

  12. μοΫλΠϐϯά

    View Slide

  13. μοΫλΠϐϯά
    w ܕ෇͚ʹؔ͢Δߟ͑ํͷҰͭ
    w ಈతܕ෇͚ݴޠͰ࢖ΘΕΔ FH3VCZ 1ZUIPO

    w ΦϒδΣΫτࣗମ͕ϝιου΍ϓϩύςΟΛ͔࣋ͭͰ൑ఆ
    OPUܕ

    r%BWF5IPNBT
    l*GJUXBMLTMJLFBEVDLBOERVBDLTMJLFBEVDL
    JUNVTUCFBEVDLz

    View Slide

  14. Ұൠతͳ੩తܕ෇͚
    ී௨ʹΫϥεࢦఆ

    ݘʹରͯ͠
    ૸Εʂ
    ϫϯʂ

    View Slide

  15. Ұൠతͳ੩తܕ෇͚
    JOUFSGBDFʹΑΔந৅Խ

    ಈ෺ʹରͯ͠
    ૸Εʂ
    ϫϯʂ

    View Slide

  16. μοΫλΠϐϯάʹΑΔ
    ಈతܕ෇͚
    Կ͔͸஌ΒΜ͕ͱΓ͋͑ͣ

    ૸Εʂ
    Կ͔͸෼͔Βͳ͍͚Ͳ
    ૸ΕͬͯݴΘΕͨΒ
    ૸Δ͸ͣ

    View Slide

  17. ϫϯʂ
    μοΫλΠϐϯάʹΑΔ
    ಈతܕ෇͚
    Կ͔͸஌ΒΜ͕ͱΓ͋͑ͣ

    ૸Εʂ

    View Slide

  18. 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];
    }

    View Slide

  19. 0CKFDUJWF$ʹ͓͚Δ
    μοΫλΠϐϯά
    walkAndQuack([Duck new]);
    // Duck walking
    // Quack!!
    walkAndQuack([Dog new]);
    // Dog walking
    // unrecognized selector sent to instance


    View Slide

  20. 0CKFDUJWF$ʹ͓͚Δ
    μοΫλΠϐϯά
    void walkAndQuack(id duck) {
    [duck walk];
    [duck quack];
    }
    walkAndQuack([Duck new]);
    walkAndQuack([Dog new]);

    View Slide

  21. 0CKFDUJWF$ʹ͓͚Δ
    μοΫλΠϐϯά
    void walkAndQuack(Duck *duck) {
    [duck walk];
    [duck quack];
    }
    walkAndQuack([Duck new]);
    walkAndQuack([Dog new]);
    *ODPNQBUJCMFQPJOUFSUZQFTQBTTJOH%PH
    UPQBSBNFUFSPGUZQF%VDL
    ܯࠂ͕ग़Δ͚ͩͰϏϧυ͸௨Δ

    View Slide

  22. 0CKFDUJWF$ͷܕγεςϜ
    w ऑ͍੩తܕ෇͚
    w ࣮ߦ࣌ʹܕͷνΣοΫΛ͠ͳ͍
    w ܕ͕Ұக͠ͳ͍ΦϒδΣΫτΛ୅ೖͯ͠΋

    ίϯύΠϧΤϥʔʹͳΒͳ͍ ܯࠂͷΈ

    w ϝιουΛݺͿࡍʹ໰୊͕͋ΔͱΫϥογϡ͢Δ
    w +BWB΍4XJGU͸ڧ͍੩తܕ෇͚

    View Slide

  23. ڧ͍ܕ෇͚ͱऑ͍ܕ෇͚
    4USJOH
    <
    ߴࡔึ೫Ռ
    Ҁ੉ֆཬ

    >
    ऑ͍ܕ෇͚
    ڧ͍ܕ෇͚

    View Slide

  24. ऑ͍ܕ෇͚
    w ࣮ߦ࣌ʹܕͷνΣοΫΛ͠ͳ͍
    w ܕͷνΣοΫΛͤͣʹϝιουΛ࣮ߦ͢Δ
    w ֨ೲ͞Ε͍ͯΔΦϒδΣΫτ͕ͦͷϝιουΛ࣮ߦͰ
    ͖Ε͹0,
    %FMFHBUF

    View Slide

  25. @protocol UITableViewDataSource
    @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ͱμοΫλΠϐϯά
    ࣮૷Λڧ੍͠ͳ͍ϝιου܈

    View Slide

  26. @implementation UITableView
    ɾ
    ɾ
    ɾ
    - (NSInteger)numberOfSections
    {
    if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) {
    return [self.dataSource numberOfSectionsInTableView:self];
    } else {
    return 1;
    }
    }
    ɾ
    ɾ
    ɾ
    @end
    %FMFHBUFͱμοΫλΠϐϯά
    ϝιου͕࣮૷͞Ε͍ͯΔ͔νΣοΫ

    View Slide

  27. %FMFHBUFͱμοΫλΠϐϯά
    @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)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    ɾɾɾ
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ɾɾɾ
    }
    @end
    ϓϩτίϧએݴ
    σϦήʔτϝιου

    View Slide

  28. %FMFHBUFͱμοΫλΠϐϯά
    @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)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    ɾɾɾ
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ɾɾɾ
    }
    @end
    OVNCFS0G4FDUJPOT*O5BCMF7JFX͕࣮૷͞Ε͍ͯͳ͍ͷͰTFDUJPO͸

    View Slide

  29. %FMFHBUFͱμοΫλΠϐϯά
    @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
    OVNCFS0G4FDUJPOT*O5BCMF7JFX͕࣮૷͞ΕͯΛฦ͢Α͏ʹ

    View Slide

  30. @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%[email protected]/VMMBCMFGSPN
    JODPNQBUJCMFUZQF)[email protected]@TUSPOH
    ϓϩτίϧએݴΛফͯ͠Έͨ৔߹
    ܯࠂ͕ग़Δ͚ͩͰϏϧυ͸௨Δ
    Ϋϥογϡ΋ͤͣ5BCMF7JFXͱͯ͠ػೳ͢Δ

    View Slide

  31. JEܕ

    View Slide

  32. JEܕ
    w 0CKFDUJWF$ಠࣗͷ൚༻σʔλܕ
    w +BWBͰݴ͏0CKFDUɺ4XJGUͰݴ͏"OZ
    w ΦϒδΣΫτͷϙΠϯλΛอ࣋
    w Ωϟετ͢Δ͜ͱͳ͘୅ೖ΍ϝιουݺͼग़͕͠Մೳ
    w ܕ҆શੑΛࣺͯͯॊೈੑʹεςʔλεΛৼͬͯΔ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  39. NSArray *> *array = @[
    @{@"hoge":@"fuga"},
    @"hogehoge"
    ];
    for (NSDictionary *obj in array) {
    NSLog([obj objectForKey:@"hoge"]);
    }
    -JHIUXFJHIU(FOFSJDT
    0CKFDUPGUZQF/44USJOHJTOPUDPNQBUJCMFXJUIBSSBZ
    FMFNFOUUZQF/4%JDUJPOBSZ/44USJOH JE

    View Slide

  40. 6TFS%FGBVMUTͱμοΫλΠϐϯά

    View Slide

  41. w ऑ͍੩తܕ෇͚
    w ࣮ߦ࣌ʹܕͷνΣοΫΛ͠ͳ͍
    w ܕͷνΣοΫΛͤͣʹϝιουΛ࣮ߦ͢Δ
    w ֨ೲ͞Ε͍ͯΔΦϒδΣΫτ͕ͦͷϝιουΛ࣮ߦͰ͖Ε͹0,
    6TFS%FGBVMUTͱμοΫλΠϐϯά
    /46TFS%FGBVMUT͕͍࣋ͬͯΔ
    ϝιουΛͦͬ͘ΓਅࣅͨΫϥεΛ࡞ِͬͯ૷ͯ͋͛͠Δ

    View Slide

  42. .PDL6TFS%FGBVMUT

    View Slide

  43. .PDL6TFS%FGBVMUT
    IUUQTHJUIVCDPN,*.PDL6TFS%FGBVMUT

    View Slide

  44. %FNP

    View Slide

  45. ஫ҙ
    w μοΫλΠϐϯάࣗମ͸͋͘·Ͱख๏ ߟ͑ํ
    Ͱ͋Γɺ

    ภʹࠇຐज़ͩͱ͸ݴ͍੾Εͳ͍
    w ࣮ࡍɺ1ZUIPO΍1)1ͳͲͷಈతܕ෇͚ܥݴޠͰ͸͜ͷ
    ߟ͑ํʹج͍ͮͨϓϩάϥϛϯά͕ߦΘΕΔ
    w ࢍ൱͸͋Δ͕ɺ͜ΕͰϙϦϞʔϑΟζϜΛ࣮ݱ͍ͯ͠Δ
    ͱ͍͏આ΋͋Δ

    View Slide

  46. ·ͱΊ
    w 0CKFDUJWF$͸ऑ͍ܕ෇͚ͳͷͰશؔ͘܎ແ͍ΫϥεͷΦ
    ϒδΣΫτΛ୅ೖͰ͖Δ
    w μοΫλΠϐϯάʹΑͬͯ/46TFS%FGBVMUTͱಉ͡ϝ
    ιουΛએݴͨ͠ผͷΫϥεΛએݴِͯ͠૷͕Մೳʹ
    w JEܕΛ࢖͏͜ͱͰΩϟετ΋ෆཁ

    View Slide

  47. 5IBOLZPV
    IUUQTHJUIVCDPN,*.PDL6TFS%FGBVMUT

    View Slide

  48. ࢀߟจݙ
    w μοΫɾλΠϐϯά 8JLJQFEJB

    IUUQTKBXJLJQFEJBPSHXJLJ
    &&&"'&##&
    #'&"&&#&
    #

    w JEܕͱ͸ಈత݁߹ͷ֓೦

    IUUQTKQSPHSBNFSDPNPCKFDUJWFD

    w ·ͭ΋ͱ௚఻ɹϓϩάϥϛϯάͷΦΩςୈճʢʣ

    IUUQTUFDIOJLLFJCQDPKQJUBSUJDMF$0-6./


    View Slide

  49. ʲॏཁͳ஫ҙࣄ߲ʳ
    ɾຊࢿྉ͸ɺஅఆత൑அΛఏڙ͢Δ΋ͷͰ͸ͳ͘ɺ৘ใΛఏڙ͢Δ͜ͱͷΈΛ໨తͱ͓ͯ͠Γɺ͍͔ͳΔछྨ
    ͷ঎඼΋ק༠͢Δ΋ͷͰ͸͋Γ·ͤΜɻ࠷ऴతͳܾఆ͸ɺ͓٬༷ࣗ਎Ͱ൑அ͢Δ΋ͷͱ͠ɺ౰ࣾ͸͜ΕʹҰ੾
    ؔ༩ͤͣɺ·ͨɺҰ੾ͷ੹೚Λෛ͍·ͤΜɻ
    ɾຊࢿྉʹ͸কདྷͷग़དྷࣄʹؔ͢Δ༧૝ؚ͕·Ε͍ͯΔ৔߹͕͋Γ·͕͢ɺͦΕΒ͸༧૝Ͱ͋Γɺ·ͨɺຊࢿ
    ྉͷ಺༰ͷਖ਼֬ੑɺ৴པੑɺ׬શੑɺద࣌ੑ౳ΛҰ੾อূ͢Δ΋ͷͰ͸͋Γ·ͤΜɻຊࢿྉʹج͍ͮͯඃͬͨ
    ͍͔ͳΔଛ֐ʹ͍ͭͯ΋ɺ౰ࣾ͸Ұ੾ͷ੹೚Λෛ͍·ͤΜɻ·ͨɺ౰ࣾ͸ɺ৽͍͠৘ใ΍কདྷͷग़དྷࣄͦͷଞ
    ͷ৘ใʹ͍ͭͯɺߋ৽ຢ͸గਖ਼͢Δٛ຿Λෛ͍·ͤΜɻ
    ɾຊࢿྉΛར༻͢Δ͜ͱʹΑΓ͓٬༷ʹੜͨ͡௚઀తଛ֐ɺؒ઀తଛ֐ɺ೿ੜతଛ֐ͦͷଞ͍͔ͳΔଛ֐ʹͭ
    ͍ͯ΋ɺ౰ࣾ͸Ұ੾ͷ੹೚Λෛ͍·ͤΜɻ
    ঎߸౳ɿ΢ΣϧεφϏגࣜձࣾۚ༥঎඼औҾۀऀؔ౦ࡒ຿ہ௕ʢۚ঎ʣୈ߸
    Ճೖڠձɿ೔ຊূ݊ۀڠձҰൠࣾஂ๏ਓ೔ຊ౤ࢿސ໰ۀڠձ

    View Slide