我正在尝试编写一个快速/灵活的测试,该测试将在打开屏幕后确认屏幕上的一些内容。 打开的屏幕只是一个按钮,用于引导 oauth2 登录以验证用户。 我只是想知道如何才能欺骗登录以便进入下一个屏幕。 我知道这可能不是很多信息,但我对 swift 的整体测试方面确实很陌生,但我知道进行单元测试非常重要。
这里是可能有帮助的代码:
import UIKit
class ViewController: UIViewController, GIDSignInDelegate, GIDSignInUIDelegate {
@IBOutlet weak var signInButton: GIDSignInButton!
@IBOutlet weak var errorLabel: UILabel!
var googleViewController: GoogleViewController!
var permittedList:[String] = ["[email protected]"]
let env = NSProcessInfo.processInfo().environment
override func viewDidLoad() {
self.view.backgroundColor = UIColor(rgb: 0x6a737b)
super.viewDidLoad()
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().clientID = env["CLIENT_ID"] as? String
GIDSignIn.sharedInstance().signInSilently()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "googledisplay" {
googleViewController = segue.destinationViewController as! GoogleViewController
}
}
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
println(error)
}
else {
if !contains(permittedList, GIDSignIn.sharedInstance().currentUser.profile.email) {
GIDSignIn.sharedInstance().signOut()
GIDSignIn.sharedInstance().disconnect()
self.errorLabel.text = "You must sign in with a permitted email address"
}
else{
self.errorLabel.text = ""
performSegueWithIdentifier("googledisplay", sender: self)
}
}
}
}
测试:
import Foundation
import Quick
import Nimble
import PasswordRecovery
class PasswordViewControllerSpec: QuickSpec {
var viewController = PasswordViewController()
override func spec() {
let _ = PasswordViewController().view
viewController.setNewEmail("[email protected]")
viewController.setNewLRA("unknown")
viewController.reset_code(t: 1447267160)
expect(self.viewController.getLRA()).to(equal("LRA"))
}
}
PasswordViewController 是在原始屏幕之后加载的视图的名称。 感谢您的帮助,如果还有什么需要请告诉我!
这是一个很好的问题。您正在努力测试代码这一事实实际上表明您需要使代码更具可测试性。
这里的问题是控制器与第三方的谷歌登录高度耦合,因此在测试中您也将测试谷歌登录代码。
因此,作为理想的解决方案,我建议将所有谷歌登录代码移至单独的类中,并使用协议来替换测试中的实现。
protocol SignInFlow {
func signIn(completion: @escaping (Result<Void, Error>) -> ())
}
final class GoogleSignInFlow: NSObject, SignInFlow, GIDSignInDelegate, GIDSignInUIDelegate {
struct SignInError: LocalizedError {
var errorDescription: String? = "You must sign in with a permitted email address"
}
private var completion: (Result<Void, Error>) -> () = { _ in }
private weak var presentingViewController: UIViewController?
func signIn(completion: @escaping (Result<Void, Error>) -> ()) {
guard let presentingViewController else { return }
self.completion = completion
GIDSignIn.sharedInstance().signIn() // Note: using .signInWithPresentationController(_:completion:) here would be better as it will not require storing the completion handler
}
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
if let err = error {
onError(.failure(error))
}
else {
if !contains(permittedList, GIDSignIn.sharedInstance().currentUser.profile.email) {
GIDSignIn.sharedInstance().signOut()
GIDSignIn.sharedInstance().disconnect()
onError(.failure(SignInError()))
}
else{
completion(.success(()))
}
}
}
}
class ViewController: UIViewController {
@IBOutlet weak var signInButton: GIDSignInButton!
@IBOutlet weak var errorLabel: UILabel!
var signInFlow: SignInFlow!
...
@objc
private func onSignInButtonTapped() {
signInFlow.signIn {
switch $0 {
case .failure(let error):
self.errorLabel.text = error.localizedDescription
case .success:
self.errorLabel.text = ""
performSegueWithIdentifier("googledisplay", sender: self)
}
}
...
}
然后你就可以在测试中存根它:
import Foundation
import Quick
import Nimble
import PasswordRecovery
final class AlwaysSucceedingSignInFlow: SignInFlow {
func signIn(completion: @escaping (Result<Void, Error>) -> ()) {
completion(.success(()))
}
}
class PasswordViewControllerSpec: QuickSpec {
var viewController = PasswordViewController()
override func spec() {
viewController.signInFlow = AlwaysSucceedingSignInFlow()
let _ = PasswordViewController().view
viewController.setNewEmail("[email protected]")
viewController.setNewLRA("unknown")
viewController.reset_code(t: 1447267160)
expect(self.viewController.getLRA()).to(equal("LRA"))
}
}
为了为该控制器提供一个像样的测试套件,还有更多的事情要做,但这超出了问题的范围