class ViewController: UIViewController { @IBOutlet weak var xTextField: UITextField! @IBOutlet weak var yTextField: UITextField! @IBOutlet weak var resultLabel: UILabel! @IBOutlet weak var urlTextField: UITextField! @IBOutlet weak var responseTextView: UITextView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.clearData() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func clearData(){ self.resultLabel.text = "" self.responseTextView.text = "" } @IBAction func calculateButton_Touch(_ sender: Any) { let x = Math.stringToInt(string: self.xTextField.text) let y = Math.stringToInt(string: self.yTextField.text) var outputString = "invalid input" if let x = x, let y = y { let result = Math.add(x: x, y: y) outputString = "\(result)" } self.resultLabel.text = outputString } @IBAction func requestButton_Touch(_ sender: Any) { if let url = urlTextField.text { Network.dataTask(urlString: url) { (data, response, error) in guard error == nil else { self.responseTextView.text = "\(error!.localizedDescription)" return } if let data = data { if let jsonString = String(data: data, encoding: .utf8){ DispatchQueue.main.async { self.responseTextView.text = jsonString class ViewController: UIViewController {
@IBOutletweakvar xTextField: UITextField!@IBOutletweakvar yTextField: UITextField!@IBOutletweakvar resultLabel: UILabel!@IBOutletweakvar urlTextField: UITextField!@IBOutletweakvar responseTextView: UITextView!overridefuncviewDidLoad() { super.viewDidLoad()// Do any additional setup after loading the view, typically from a nib. }overridefuncviewWillAppear(_animated: Bool) { super.viewWillAppear(animated) self.clearData() }overridefuncviewDidAppear(_animated: Bool) { super.viewDidAppear(animated) }overridefuncdidReceiveMemoryWarning() { super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated. }funcclearData(){ self.resultLabel.text="" self.responseTextView.text="" }@IBActionfunccalculateButton_Touch(_sender: Any) {let x = Math.stringToInt(string: self.xTextField.text)let y = Math.stringToInt(string: self.yTextField.text)var outputString ="invalid input"iflet x = x, let y = y {let result = Math.add(x: x, y: y) outputString ="\(result)" } self.resultLabel.text= outputString }@IBActionfuncrequestButton_Touch(_sender: Any) {iflet url = urlTextField.text { Network.dataTask(urlString: url) { (data, response, error) inguard error ==nilelse { self.responseTextView.text="\(error!.localizedDescription)"return }iflet data = data {iflet jsonString =String(data: data, encoding: .utf8){ DispatchQueue.main.async { self.responseTextView.text= jsonString } } } } } }}
(2.) Math
add: 將2個數字相加並回傳
stringToInt: string轉int並回傳結果, 若失敗回傳nil
classMath:NSObject {classfuncadd(x: Int, y: Int) ->Int {let result = x + yreturn result }classfuncstringToInt(string: String?) ->Int? {var result:Int?=niliflet string = string { result =Int(string) }return result }}
importXCTestclassTestProjectTests:XCTestCase {overridefuncsetUp() { super.setUp()// Put setup code here. This method is called before the invocation of each test method in the class. }overridefunctearDown() {// Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() }functestExample() {// This is an example of a functional test case.// Use XCTAssert and related functions to verify your tests produce the correct results. }functestPerformanceExample() {// This is an example of a performance test case. self.measure {// Put the code you want to measure the time of here. } }}
我們可以注意到, Unit Test用的class必須import XCTest並extend XCTestCase,
importXCTestclassMathTest:XCTestCase {overridefuncsetUp() { super.setUp()// Put setup code here. This method is called before the invocation of each test method in the class. }overridefunctearDown() {// Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() }functestAdd() {let a = Math.add(x:3, y:5)let b = Math.add(x:64, y:-70)let c = Math.add(x:999, y:0)XCTAssert(a ==8, "a should be 8")XCTAssert(b ==-6, "b should be -6")XCTAssert(c ==999, "c should be 999") }functestStringToInt() {let a = Math.stringToInt(string:"9")let b = Math.stringToInt(string:"-55")let c = Math.stringToInt(string:"sdfsks")XCTAssert(a ==9, "a should be 8")XCTAssert(b ==-55, "b should be -55")XCTAssert(c ==nil, "c should be nil") }}
importXCTestclassTestNetwork:XCTestCase {overridefuncsetUp() { super.setUp()// Put setup code here. This method is called before the invocation of each test method in the class. }overridefunctearDown() {// Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() }functestDataTask() {let urlString ="http://opendata2.epa.gov.tw/UV/UV.json" Network.dataTask(urlString: urlString) { (data, response, error) inlet requestUrl = response?.url?.absoluteStringXCTAssert(requestUrl == urlString, "wrong URL!") } }}
(1.) test class的Viewcontroller需要用storyboard.instantiateViewController的方式去宣告, 否則IBOutlet元件會為nil
(2. ) 必須呼叫 vc.loadView() 才能啟動Viewcontroller的生命週期
importXCTestclassTestViewController:XCTestCase {overridefuncsetUp() { super.setUp() }overridefunctearDown() {// Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() }functestClearData() {let storyboard =UIStoryboard(name:"Main", bundle: Bundle(for: ViewController.self))let vc = storyboard.instantiateViewController(withIdentifier:"ViewController")as! ViewController vc.loadView()// call life cycle vc.clearData()XCTAssert(vc.resultLabel!.text=="", "vc.resultLabel!.text should be empty ")XCTAssert(vc.responseTextView!.text=="", "vc.responseTextView!.text should be empty ") }}