2017-01-01 5 views
1

오늘은 BDD 방식으로 iOS 유닛 테스트를 작성하기 시작했습니다. guard 진술과 100 % 코드 커버리지에 관한 질문이 있습니다.Guard Statement 테스트 통과를위한 테스트 커버리지 방법

Data에서 Customer 개체로의 변환을 처리하는 다음 코드가 있습니다.

internal final class func customer(from data: Data) -> Customer? { 
    do { 
     guard let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: []) as? Dictionary<String, Any> else { 
      return nil 
     } 
     var customerFirstName: String? = nil 
     var customerLastName: String 
     if let firstName = jsonDictionary["first_name"] as? String { 
      customerFirstName = firstName 
     } 
     guard let lastName = jsonDictionary["last_name"] as? String else { 
      return nil 
     } 
     customerLastName = lastName 
     return Customer(firstName: customerFirstName, lastName: customerLastName) 
    } catch { 
     return nil 
    } 
} 

우리 백엔드를 만들었을 때 일부 고객에게는 이름과 성이 포함 된 성이 주어졌습니다. 그래서 고객의 이름은 선택 사항입니다. 그들의 성명은 last_name의 값일 수 있습니다.

내 코드에서 고객의 성은 선택적이지만 성이 필수입니다. 네트워크 요청에서 수신 된 JSON에 성이 반환되지 않으면 고객을 만들지 않습니다. 또한 DataDictionary으로 직렬화 할 수없는 경우 고객이 생성되지 않습니다.

둘 다 두 시나리오를 테스트하기 위해 사용하고있는 고객 정보가 포함 된 두 개의 JSON 파일이 있습니다.

{ 
    "first_name": null, 
    "last_name": "Test Name", 
} 

다른 하나는 먼저 JSON의 이름이 포함되어 있습니다 : 빠르고 민첩한를 사용하여 내 단위 테스트에서

{ 
    "first_name": "Test", 
    "last_name": "Name", 
} 

를, 내가 처리

하나는 JSON에는 이름을 포함하지 않는다 첫 번째 이름을 사용할 수 없을 때 Customer을 만들면 그 이름은 다음과 같습니다.

override func spec() { 
    super.spec() 
    let bundle = Bundle(for: type(of: self)) 
    describe("customer") { 
     context("whenAllDataAvailable") { 
      it("createsSuccessfully") { 
       let path = bundle.path(forResource: "CustomerValidFullName", ofType: "json", inDirectory: "ResponseStubs")! 
       let url = URL(fileURLWithPath: path) 
       let data = try! Data(contentsOf: url) 
       let customer = DataTransformer.customer(from: data) 
       expect(customer).toNot(beNil()) 
      } 
     } 
     context("whenMissingLastName") { 
      it("createsUnsuccessfully") { 
       let path = bundle.path(forResource: "CustomerMissingLastName", ofType: "json", inDirectory: "ResponseStubs")! 
       let url = URL(fileURLWithPath: path) 
       let data = try! Data(contentsOf: url) 
       let customer = DataTransformer.customer(from: data) 
       expect(customer).to(beNil()) 
      } 
     } 
    } 
} 

이것은 반환 된 JSON에 이름이 없거나 존재할 때 Customer을 생성합니다.

데이터가 유효한 JSON 개체로 바뀔 수 있기 때문에 내 코드가 else 절의 else 절을 누르지 않으면 BDD를 사용하여이 방법의 코드 적용 범위를 100 %까지 어떻게 늘릴 수 있습니까? 다른 .json 파일을 Customer이 생성되지 않고 Customer이 생성되지 않도록 last_name을 포함하는 파일뿐만 아니라 .json 파일이 생성되지 않도록 JSON 객체로 변환 할 수없는 데이터를 추가해야합니까?

나는 "100 % 코드 적용 범위"개념을 과소 평가하고 있습니까? guard 문장의 else 절을 테스트해야 할 필요가 있습니까? BDD 방법을 사용하여 적절한 방법을 사용하고 있습니까?

답변

1

당신이 생각할 수있는 모든 방식으로 잘못된 JSON을 작성하십시오. 예 :

  • 올바른 JSON이 아닌 것으로 예외 처리를 수행 할 수 있습니다.
  • 처음에는 guard을 사전이 아닌 JSON 배열로 칠할 수 있습니다.

말처럼 올바른 코드를 작성하면됩니다.

TDD와 BDD가 관련되어 있습니다.TDD에서는 먼저 실패한 테스트를 작성합니다. 그런 다음 가능한 빨리 테스트를 통과시키는 코드를 작성하십시오. 마지막으로 코드를 정리하여 코드를 개선하십시오. 사실 테스트를 추가하는 것 같습니다.

그런데 외부 파일을 사용하지 않으면 테스트가 훨씬 명확 해 지지만 테스트에 JSON을 직접 넣으면됩니다. 다음은 TDD에서 JSON 변환의 시작을 보여주는 스크린 캐스트입니다. 스크린 캐스트는 Objective-C에 있지만 원리는 같습니다. http://qualitycoding.org/tdd-json-parsing/

+0

@JonRein 통찰력에 감사드립니다! 나는 사실을 모른 채 시험을 쓴다고 어떻게 결론 내 렸습니까? 그것이 바로 내가 한 일이지만, 당신을 그 결론에 이르게 한 이유가 궁금합니다. 나는 확실히 당신의 개념을 연구하고 더 나은 이해를 얻기를 바라고 있습니다. –

+0

@NickKohrn 코드가 테스트 주도 일 때 테스트를 만족하지 않는 코드를 작성하지 않기 때문에. 그래서 당신은 결국 "나는 어떤 코드를 가지고있다. 어떻게 커버 할 수 있는가?"라고 묻지는 않는다. –