2017-03-03 1 views
0

Ich bin in einer Situation, in der ich versuche, Test Driven Development zu verwenden. Ich habe keine Erfahrung mit Swift, Xcode, Apple, IOS, TDD oder sogar dem MacBook, das ich für die Entwicklung verwende. Im Grunde bin ich ein .NET Entwickler in einer sehr ungewohnten Situation.Test Driven Upload-Methode?

Mein aktuelles Problem ergibt sich aus meiner Unkenntnis, wie man einen Unit-Test macht, der eine void-Methode testet.

Ich versuche, eine Methode zu erstellen, die ein Bild an einen Server sendet.

Aber mein Problem hier ist, dass ich nicht weiß, wie man eine Methode prüft, die keinen Wert zurückgibt.

Ich stelle mir vor, dass meine Methode etwas ähnliches wie dies sein wird:

public func Upload(_ image: UIImage) 

und ich denke, dass muss ich werde einige Version von URLSession implementieren, müssen schließlich eine resume() Methode aufrufen. Aber wie kann ich testen, ob diese Methode das tut, was sie tun soll, ohne das Netzwerk aufzurufen? und danach, wie mache ich einen Integrationstest, bei dem ich sehen kann, dass das erwartete Ergebnis tatsächlich eine Datei ist, die auf den Server hochgeladen wurde? Momentan befindet sich der Server auf dem Computer, auf dem ich gerade entwickle, aber die eigentliche Software läuft von einem TestIphone, das mir ausgestellt wurde. Teil der Lösung sein wird, nicht die Prüfung der Lösung

Ich habe jetzt Tagen online gesucht und das Beste, was ich habe diesen Link http://swiftdeveloperblog.com/image-upload-with-progress-bar-example-in-swift/ über gewesen kommen Aber es läuft nur Bits und Stücke, die ich vorstellen.

Ich denke, es ist wichtig hinzuzufügen, ich bin sehr gegen die Erstellung zu viel Komplexität für Testzwecke. Testen sollte einfach und unkompliziert sein.

Antwort

2

Der Ansatz zu nehmen ist, ein Test-Doppel zu verwenden, um zu überprüfen, dass die richtigen Netzwerkanrufe von Ihrer upload Methode vorgenommen werden. Sie führen einen asynchronen Anruf bei einer Netzwerkbibliothek aus, die URLSession oder eine andere Bibliothek wie AlamoFire sein kann. Es sollte für Ihre upload Methode keine Rolle spielen, welche Bibliothek verwendet wird.

Um dies zu erreichen, möchten Sie die direkte Verwendung von URLSession vermeiden und einen Wrapper verwenden, der einer Schnittstelle entspricht, die Sie dann in Ihren Tests nachahmen können. Dies bedeutet, dass Ihr Code zur Laufzeit eine andere Implementierung der Netzwerkklasse verwendet als zum Testzeitpunkt, und Sie "injizieren" den richtigen Code nach Bedarf.

Zum Beispiel könnten Sie diese Schnittstelle zu Ihrer Netzwerk-Bibliothek:

protocol NetworkRequesting { 
    func post(data: Data, url: URL) 
} 

Mit der folgenden realen Implementierung zur Laufzeit verwendet werden:

struct NetworkRequester: NetworkRequesting { 
    func post(data: Data, url: URL) { 
     let session = URLSession() 
     let task = session.uploadTask(with: URLRequest(url: url), from: data) 
     task.resume() 
    } 
} 

jedoch bei Testzeit, verwenden Sie der folgende Schein stattdessen:

class MockNetworkRequester: NetworkRequesting { 
    var didCallPost = false 
    var spyPostData: Data? = nil 
    var spyPostUrl: URL? = nil 
    func post(data: Data, url: URL) { 
     didCallPost = true 
     spyPostData = data 
     spyPostUrl = url 
    } 
} 

Und dann, angesichts der folgenden Klasse im Test:

class ImageUploader { 
    let networkRequester: NetworkRequesting 
    init(networkRequester: NetworkRequesting) { 
     self.networkRequester = networkRequester 
    } 

    func upload(image: UIImage, url: URL) { 

    } 
} 

Sie die Implementierung von upload wie so testen:

class UploadImageTests: XCTestCase { 
    func test_uploadCallsPost() { 
     let mockNetworkRequester = MockNetworkRequester() 
     let uploader = ImageUploader(networkRequester: mockNetworkRequester) 
     uploader.upload(image: UIImage(), url: URL(string:"http://example.com")!) 
     XCTAssert(mockNetworkRequester.didCallPost) 
    } 
} 

Derzeit wird dieser Test nicht als upload nichts tut, aber wenn Sie die folgenden in der Klasse unter Beweis stellen, Der Test wird bestanden:

Und das ist Ihr erster TDD-Zyklus. Offensichtlich verhält es sich noch nicht so, wie Sie es möchten, also müssen Sie einen weiteren Test schreiben, um sicherzustellen, dass die verwendete URL die erwartete ist, oder dass die übergebenen Daten Ihren Erwartungen entsprechen.

Es gibt eine Reihe von Möglichkeiten, Ihren Code zur Verwendung des realen Netzwerkrequests zur Laufzeit zu verwenden. Sie könnten die init-Methode verwenden, um NetworkRequester zu verwenden oder eine statische Factory-Methode zu verwenden. und es gibt andere Optionen wie Inversion of Control, was den Rahmen dieser Antwort sprengen würde.

Die wichtige Sache zu erinnern ist, dass Sie testen, dass Sie die richtigen Aufrufe an das Netzwerk-Framework vornehmen, testen Sie nicht das Netzwerk-Framework. Ich halte meine Protokollschnittstellen für ziemlich deklarativ und übergebe die notwendigen Dinge, um eine Anfrage in irgendeinem Rahmen zu stellen, aber du magst es bevorzugen, näher an den Metal zu gehen und die Implementierung von URLSession zu spiegeln - es liegt an dir und mehr eine Kunst als eine Wissenschaft, meiner Meinung nach.

+0

Ich mag Ihren Ansatz und ich werde das jetzt versuchen :) danke, dass Sie sich die Zeit genommen haben, mir diese Antwort zu geben – Helbo

Verwandte Themen