2016-06-19 21 views
1

HintergrundEntwerfen einer Objective-C-Klasse

Ich arbeite meistens mit Java prüfbar zu sein. Hier ist ein Code, den ich in Objective-C geschrieben habe. Mein Ziel ist es, einige Komponententests für "MyService" zu schreiben. Zu Ihrer Information: Der Name der Klasse in diesem Code ist nur ein Platzhalter.

Frage

Ist dies wie ein sinnvoller Ansatz scheinen? Ich bin:

  • Giving dieser Klasse ein Singleton-Methode (sharedMyService)
  • einen Konstruktor Deklarieren NSURLSession
  • Die Aufnahme einer Standard-Konstruktor zu injizieren, die die reale NSURLSession

Meine Absicht verwendet wird:

  • Ich möchte diesen Code durch Mockingtesten
  • würde ich spritzt, dass NSURLSession Mock in diese Klasse es
  • vermutlich auf der Apple-docs zu testen mehr lesen oder irgendwo zu sehen, wie die dataTaskWithURL: Methode zu verspotten. Hier

ist die Header-Datei:

#import <Foundation/Foundation.h> 

@interface MyService : NSObject 

@property(nonatomic, strong, readwrite) NSURLSession *session; 

+ (id)sharedMyService; 

- (instancetype)initWithURLSession:(NSURLSession *)session; 

- (void)fetchData:(NSString*)location; 

@end 

Und die Umsetzung ...

#import "MyService.h" 

@implementation MyService 

static NSString *const targetUri = @"http://something.com/%@"; 

+ (instancetype)sharedMyService { 
    static MyService *service = nil; 
    @synchronized (self) { 
     if (service == nil) { 
      service = [[self alloc] init]; 
     } 
    } 
    return service; 
} 

- (instancetype)initWithURLSession:(NSURLSession *)session { 
    self = [super init]; 
    if (self) { 
     self.session = session; 
    } 
    return self; 
} 

- (instancetype)init { 
    return [self initWithURLSession:[NSURLSession sharedSession]]; 
} 

- (NSURLSession *)getSession { 
    return self.session; 
} 

- (void)fetchData:(NSString*)location { 
    NSURL *targetUrl = [NSURL URLWithString:[NSString stringWithFormat:targetUri, location]]; 
    NSURLSession *urlSession = [self getSession]; 
    NSURLSessionTask *sessionTask = [urlSession dataTaskWithURL:targetUrl completionHandler: ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 
     NSLog(@"Request succeeded."); 
    }]; 
    [sessionTask resume]; 
} 

Antwort

2

Ein Paar zu denken, Dinge über:

  • meiner Meinung nach ist die Gestaltung iOS-Code (Objective-C oder Swift) ist das nicht anders Code in Java zu entwerfen. Es gelten die gleichen Prinzipien und Sie würden es auf die gleiche Weise tun.

  • Vermeiden Sie Singletons, wo immer es möglich ist. Beispielsweise können Sie einen Accessor für die Klasse verwenden, um den Dienst zurückzugeben, aber Sie können auch eine Methode verwenden, mit der Sie eine neue Instanz löschen, zurücksetzen oder injizieren können. Reine Singleton-Muster sind im Test-Backend ein Problem und Singletons werden in vielen iOS-Projekten oft überstrapaziert. In meinem Code, obwohl ich Singletons codieren könnte, mache ich sie im Allgemeinen auch einstellbar (auch wenn nur aus einer Kategorie in der Einheit Test Quellcode).

  • Schauen Sie in die OCMock Objective-C Mock Framework. Ich habe es seit vielen Jahren benutzt und es gibt sehr wenig, was es nicht tun kann. Sehr ähnlich wie Java-Frameworks wie Easymock und Mockito. Beachten Sie jedoch, dass, wenn Sie daran denken, Swift zu verwenden, dieses Spott für Swift so gut wie nicht existiert. Swift hat einfach nicht die Laufzeitfähigkeiten dafür.

0

"Ist dies wie ein sinnvoller Ansatz scheinen?" Ja (obwohl wir keine Ahnung haben, was Ihre Tests beweisen oder wie Ihr anderer Code diese Klasse verwenden wird).

Es gibt offensichtlich andere Optionen, wie die Verwendung einer Unterklasse, um zusätzliche Testbarkeit zu ermöglichen. Der Vorteil hierbei ist, dass Sie die Benutzer nicht durch die öffentliche Deklaration der Klasse als Singleton- und instanziierbare Klasse verwirren.

auch darüber nachdenken, ob ein Singleton ist wirklich der richtige Weg für Sie - tun Sie jemals in der Lage sein, diese Klasse wieder zu verwenden mit verschiedenen Sitzungen - und ob eine Fabrik Ansatz wäre besser ...

+0

Thanks @ josh-caswell überprüft nur die Bedeutung meiner misspelling: -S – Wain

+0

Huh, habe ich nicht einmal wissen, dass es ein Wort war! :) –