2017-08-25 48 views
6

Próbuję przetestować wygląd etykiety (toastLabel), którą mam animację, która pojawia się krótko, gdy ktoś wprowadzi niewłaściwy adres e-mail.Testowanie animowanej etykiety, która pojawia się i znika

private func registerNewUser(email: String, password: String, confirmationPassword: String) { 
    if password == confirmationPassword { 
     firebaseData.createUser(email: email, password: password, completion: { (error, _) in 
      if let error = error { 
       self.showToast(in: self.view, with: error.localizedDescription) 
      } else { 
       self.showToast(in: self.view, with: "Registered succesfully") 
       self.signInUser(email: email, password: password) 
      } 
     }) 
    } else { 
     //raise password mismatch error 
     print("password mismatch error") 
    } 
} 

func showToast(in toastSuperView: UIView, with text: String) { 
    let toastLabel = ToastLabel() 
    toastLabel.text = text 
    toastSuperView.addSubview(toastLabel) 
    layoutToastLabel(toastLabel) 
    animateToastLabel(toastLabel) 
} 

private func layoutToastLabel(_ toastLabel: ToastLabel) { 
    toastLabel.centerYToSuperview() 
    toastLabel.pinToSuperview(edges: [.left, .right]) 
} 

private func animateToastLabel(_ toastLabel: ToastLabel) { 
    UIView.animate(withDuration: 2.5, delay: 0, options: .curveEaseOut, animations: { 
     toastLabel.alpha = 0.0 
    }, completion: { _ in 
     toastLabel.removeFromSuperview() 
    }) 
} 

Chcę po prostu sprawdzić, czy tekst błędu otrzymał z powrotem pojawia Firebase po wejściu użytkownika e-mail, które zostały już podjęte.

Kiedy korzystam z innych narzędzi, takich jak oczekiwanie i XCTWaiter, testy nadal nie przechodzą mimo niezaprzeczalnego tekstu i etykiety. Nigdy nie musiałem wykonywać takich testów, więc nie jestem pewien, gdzie mogę pójść źle, czy muszę zrobić coś innego, aby przetestować animowany widok lub coś takiego.

Update1:

Więc widzę po nieco bardziej, że kiedy gra dotknij registerButton tosty pojawia się tak jak powinien, ale test nie będzie kontynuowana, dopóki nie zniknął. Uważam, że to dziwne, ponieważ nie jest ściśle związane z registerButton jest własnym zdaniem.

Update2:

mam zaktualizować mój test następująco:

func testRegisteringWithUsedEmailDisplaysFirebaseError() { 

    welcomeScreenHelper.register(email: registeredEmail, 
           password: password, 
           confirmationPassword: password, 
           completion: { 

     let firebaseErrorMessage = "The email address is already in use by another account." 

     let text = self.app.staticTexts[firebaseErrorMessage] 
     let exists = NSPredicate(format: "exists == true") 

     self.expectation(for: exists, evaluatedWith: text, handler: nil) 
     self.waitForExpectations(timeout: 10, handler: nil) 
     XCTAssert(self.app.staticTexts[firebaseErrorMessage].exists) 
    }) 
} 

z dodatkiem:

override func setUp() { 
    app.launch() 
    UIView.setAnimationsEnabled(false) 
    super.setUp() 
} 

override func tearDown() { 
    if let email = createdUserEmail { 
     firebaseHelper.removeUser(with: email) 
    } 
    UIView.setAnimationsEnabled(true) 
    super.tearDown() 
} 

Ale do tej pory nie ma szczęścia. Wciąż widzę, że po kliknięciu przycisku rejestru na grzbiecie pojawia się toast, a kolejna linia nie jest wywoływana, dopóki toastLabel nie zakończy animacji.

+0

Trudno jednak dostrzec problem w kodzie - istnieją pewne sposoby, ale brakuje kontekstu. Podobnie jak: 'func testRegisteringWithUsedEmailDisplaysFirebaseError()' jest zdecydowanie w 'klasie MyTest: XCTestCase'; to 'func register (email: String, password: String, confirmationPassword: String, completion: (() -> Void)? = nil)' również metoda 'MyTest'? Wydaje się, że to metoda pośrednia. Czy w jakiś sposób wstrzykujesz 'firebaseData'? Podanie większej ilości kontekstu zdecydowanie poprawiłoby jakość pytania. –

+0

Sprawdź poprawkę –

Odpowiedz

3

Istnieje kilka rzeczy, które trzeba rozwiązać w taki rodzaj Test:

  1. Jeśli kod testujesz korzysta DispatchQueue.async należy użyć XCTestCase.expectation
  2. Jeśli testowany kod ma numer UIView.animate (widzę, że jest taki w twoim przykładzie), wykonaj przed testem UIView.setAnimationsEnabled(false) i włącz go po zakończeniu testu, aby oczekiwanie nie czekało na zakończenie animacji. Możesz to zrobić metodami XCTestCase.setUp i XCTestCase.tearDown.
  3. Jeśli testowany kod ma zależności, takie jak usługi wykonujące połączenia asynchroniczne (zakładam, że jest to firebaseData), należy wstrzyknąć swoje makiety/kody pośredniczące, które będą się zachowywać synchronicznie lub używać XCTestCase.expectation i modlić się, aby interfejs API/sieć były prawidłowe, podczas gdy testy są uruchamiane.

Używanie XCTestCase.expectation + UIView.setAnimationsEnabled(false) powinno zadziałać. Tylko XCTestCase.expectation z odpowiednio wysokim czasem oczekiwania powinno działać.

EDIT 1: poprawny sposób używać oczekiwania:

func test() { 
    let exp = expectation(description: "completion called") 
    someAsyncMethodWithCompletion() { 
     exp.fulfill() 
    } 
    waitForExpectations(timeout: 1) { _ in } 
    // assert here 
} 

Więc metoda badania powinny być:

func testRegisteringWithUsedEmailDisplaysFirebaseError() { 
    let exp = expectation(description: "completion called") 
    welcomeScreenHelper.register(email: registeredEmail, 
           password: password, 
           confirmationPassword: password, 
           completion: { exp.fulfill() }) 
    self.waitForExpectations(timeout: 10, handler: nil) 
    let firebaseErrorMessage = "The email address is already in use by another account." 
    XCTAssert(self.app.staticTexts[firebaseErrorMessage].exists) 
} 
+1

Cześć, dziękuję za odpowiedź, kod w ogóle nie korzysta z DispatchQueue, ale korzysta z UIView.animate na toast. Zrobiłem to, o czym wspomniałeś, jak widać w mojej aktualizacji2 w pytaniu, ale otrzymałem taki sam nieudany rezultat. Odnośnie do twojego innego komentarza nie kpię ani nie upieram niczego, metoda 'register' jest po prostu zawarta w klasie pomocnika, a baza ogniowa nie jest wstrzykiwana gdziekolwiek, ale jest wywoływana, jeśli nie ma błędów w tym, co użytkownik wprowadził. Błędy są przedstawiane w toście, co próbuję przetestować. Dzięki – Wazza

-1

Zamiast etykietę można spróbować domyślnie UIAlertController podobnie jak ten

func toast(message: String!) -> Void { 

     let controller: UIAlertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) 
     self.present(controller, animated: true, completion: nil) 
     let when = DispatchTime.now() + 2.5 // change 2.5 to desired number of seconds 
     DispatchQueue.main.asyncAfter(deadline: when) { 
      // Your code with delay 
      self.dismiss(animated: true, completion: nil) 
     } 

    } 

jest to prosty sposób, aby pokazać tosty w iOS

+0

Dziękuję za odpowiedź, ale chcę, aby był to widok niestandardowy. Dodatkowo moje pytanie dotyczy zaliczenia testu. – Wazza