2017-03-03 7 views
0

저는 Test Driven Development를 사용하려고합니다. Swift, Xcode, Apple, IOS, TDD 또는 개발 용 MacBook에 익숙하지 않았습니다. 기본적으로 저는 매우 익숙하지 않은 상황에서 .Net 개발자입니다.시험 구동 업로드 방법은 무엇입니까?

내 현재의 문제는 무효화 방법을 테스트하는 단위 테스트를 만드는 방법에 대한 내 무지에서 비롯됩니다.

이미지를 서버로 보내는 방법을 만들고 있습니다.

그러나 여기 내 문제는 값을 반환하지 않는 메서드를 테스트하는 방법을 모른다는 것입니다.

public func Upload(_ image: UIImage) 

와 나는 결국 resume() 메소드를 호출해야합니다 URLSession의 일부 버전을 구현해야합니다 상상 :

나는 내 방법이 비슷한 될 것입니다 상상. 하지만이 메소드가 네트워크를 호출하지 않고 수행중인 작업을 수행하고 있는지 테스트하려면 어떻게해야합니까? 그 후에 예상되는 결과가 사실 서버에 업로드 된 파일이라는 것을 알 수있는 통합 테스트를 어떻게해야합니까? 현재 서버는 내가 개발중인 컴퓨터에 있지만 실제 소프트웨어는 내가 발행 한 testIphone에서 실행됩니다.

나는 지금까지 온라인으로 검색을 해왔으며, 내가 본 링크 중 가장 좋은 것은이 링크였습니다. http://swiftdeveloperblog.com/image-upload-with-progress-bar-example-in-swift/ 하지만 솔루션의 테스트가 아니라 솔루션의 일부가 될 것이라고 생각합니다.

필자는 테스트 목적으로 많은 복잡성을 만드는 것을 막기 위해 추가하는 것이 중요하다고 생각합니다. 테스트는 간단하고 직선적이어야합니다.

답변

2

취해야 할 접근법은 테스트 이중을 사용하여 upload 방법으로 올바른 네트워킹 호출이 이루어 졌는지 확인하는 것입니다. URLSession 일 수도 있고 AlamoFire와 같은 다른 라이브러리 일 수도있는 네트워킹 라이브러리에 대한 비동기 호출을 작성합니다. 어느 라이브러리가 사용 중인지에 관계없이 귀하의 upload 방법을 사용해야합니다.

이렇게하려면 URLSession을 직접 사용하지 말고 테스트에서 모의 ​​할 수있는 인터페이스에 맞는 래퍼를 사용하고 싶습니다. 이는 코드가 테스트 시간보다 런타임에 네트워킹 클래스의 다른 구현을 사용한다는 것을 의미하며 필요에 따라 올바른 코드를 "주입"합니다.

예를 들어, 당신은 당신의 네트워킹 라이브러리에이 인터페이스를 할 수 : 다음 실제 구현

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

실행시 사용되는 : 시험 시간에,

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

그러나, 사용 대신 다음과 같은 가짜 :

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

그리고 다음 클래스 테스트 대상 :

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

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

    } 
} 

당신은과 같이 upload의 구현을 테스트 할 수 upload는 아무것도하지 않는 것처럼

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) 
    } 
} 

현재, 그 테스트가 실패합니다,하지만 당신은 넣을 경우 테스트중인 클래스에 다음, 테스트가 통과합니다 :

func upload(image: UIImage, url: URL) { 
    guard let otherUrl = URL(string:"https://example.org") else { return } 
    networkRequester.post(data: Data(), url: otherUrl) 
} 

그리고 이것이 첫 번째 TDD주기입니다. 분명히 원하는대로 동작하지 않으므로 사용 된 URL이 예상 한 URL인지 아니면 전달 된 데이터가 예상 한 것인지를 확인하기 위해 다른 테스트를 작성해야합니다.

런타임시 실제 네트워크 리퀘 스터를 사용하는 코드를 얻는 데는 여러 가지 방법이 있습니다. init 메소드가 기본 매개 변수 값을 사용하여 NetworkRequester을 사용하게하거나 정적 팩토리 메소드를 사용하여 만들 수 있습니다. Inversion of Control과 같은 다른 옵션이 있습니다.이 옵션은이 답변의 범위를 훨씬 벗어납니다.

기억해야 할 중요한 점은 네트워킹 프레임 워크를 테스트하지 않고 네트워크 프레임 워크에 대한 올바른 호출을 테스트한다는 것입니다. 필자는 프로토콜 인터페이스를 매우 선언적으로 유지하여 모든 프레임 워크에서 요청을하기 위해 필요한 것들을 전달하지만, 여러분은 금속에 더 가까이 가서 URLSession의 구현을 미러링하는 것을 선호 할 것입니다. 이는 여러분에게 달려 있습니다. 제 생각에는 과학보다는 예술입니다.

+0

나는 당신의 접근법을 좋아하는데, 나는 그것을 시도 할 것입니다. :) 저에게이 답을주기 위해 시간을내어 주셔서 감사합니다. – Helbo