Skip to content

Latest commit

ย 

History

History
111 lines (83 loc) ยท 4.2 KB

Testing-Tips-Tricks.md

File metadata and controls

111 lines (83 loc) ยท 4.2 KB

Testing Tips & Tricks

Session 417

๐Ÿ”— Testing Tips & Tricks - WWDC 2018 - Videos - Apple Developer

Working with Notifications

Notification ์€ 1๋Œ€ ๋‹ค๋กœ ์†Œํ†ตํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ๊ทธ๋ž˜์„œ ์˜๋„ํ•˜์ง€ ์•Š์€ ์‚ฌ์ด๋“œ ์ดํŒฉํŠธ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„๋ฆฌ๋œ ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

    class PointsOfInterestTableViewController {
        var observer: AnyObject?
        init() {
    			let name = CurrentLocationProvider.authChangedNotification
    			observer = NotificationCenter.default.addObserver(forName: name, object: nil,
    				self?.handleAuthChanged() 
    			}
    		}
        
    		var didHandleNotification = false
        func handleAuthChanged() {
            didHandleNotification = true
        }
    }

default NotificatonCenter๋ฅผ ํ†ตํ•ด observer๋ฅผ ๋“ฑ๋ก ํ•ด์ฃผ๊ณ  ์žˆ๊ณ  ์‹ค์ œ๋กœ notification์„ ๋ฐ›์•˜๋Š”์ง€ flag๊ฐ’์„ ํ†ตํ•ด ํ™•์ธ ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

    class PointsOfInterestTableViewControllerTests: XCTestCase {
    	func testNotification() {
    		let observer = PointsOfInterestTableViewController() 
    		XCTAssertFalse(observer.didHandleNotification)
    	
    		let name = CurrentLocationProvider.authChangedNotification 
    		NotificationCenter.default.post(name: name, object: nil)
    		
    		XCTAssertTrue(observer.didHandleNotification) 
    	}
    }

ViewController๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” NotificationCenter์— post ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

UIApplication๊ณผ appDidFinishLaunching ๊ฐ™์€ notification์€ ์—ฌ๋Ÿฌ ๋ ˆ์ด์–ด์—์„œ observe ํ•˜๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์‚ฌ์ด๋“œ์ดํŒฉํŠธ๊ฐ€ ์ƒ๊ธฐ๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ๊ฐ€ ๋Š๋ ค ์งˆ ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

โ†’ ํ…Œ์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

NotificationCenter ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์ธ default ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€๋งŒ, ํ•„์š”์‹œ์— ์ถ”๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์ด ํ…Œ์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ ์‹œํ‚ค๋Š” ๊ฒƒ์˜ ํ•ต์‹ฌ์ด๋‹ค.

  • .default ์ธ์Šคํ„ด์Šค ๋Œ€์‹  ์‚ฌ์šฉํ•  NotificationCeneter๋ฅผ ์ƒ์„ฑ -> Dependency Injection
    class PointsOfInterestTableViewController {
    	let notificationCenter: NotificationCenter
    	var observer: AnyObject?
    
    	init(notificationCenter: NotificationCenter = .default) {
    		self.notificationCenter = notificationCenter
    		let name = CurrentLocationProvider.authChangedNotification
    		observer = notificationCenter.addObserver(forName: name, object: nil,
    		 
    			self?.handleAuthChanged() 
    	}
    }
    
    var didHandleNotification = false
    func handleAuthChanged() {
        didHandleNotification = true
    }
    }

init ์‹œ unit tests์‹œ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ NotificatioCenter์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ์ˆ˜์ •.

    class PointsOfInterestTableViewControllerTests: XCTestCase {
        func testNotification() {
           let notificationCenter = NotificationCenter()
           let observer = PointsOfInterestTableViewController(notificationCenter:
                                                                      notificationCenter)
    				XCTAssertFalse(observer.didHandleNotification)
    		  
    			let name = CurrentLocationProvider.authChangedNotification notificationCenter.post(name: name, object: nil)
    			
    			XCTAssertTrue(observer.didHandleNotification) 
    		}
    }

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋„ NotificationCenter ์„ ๋”ฐ๋กœ ์ƒ์„ฑํ•˜๋„๋ก ์ˆ˜์ •

Mocking with Protocols

๋‹ค๋ฅธ ํด๋ž˜์Šค๋‚˜ SDK ๋“ฑ๊ณผ ์ƒํ˜ธ์ž‘์šฉ ํ•˜๋Š” ํด๋ž˜์Šค๋Š” ์™ธ๋ถ€ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๊ฑฐ๋‚˜ ํ˜น์€ ์•„์˜ˆ ๋ถˆ๊ฐ€๋Šฅ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ…Œ์ŠคํŠธ ์ž‘์„ฑํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค. ํŠนํžˆ ์ง์ ‘ ์ƒ์„ฑ ํ•  ์ˆ˜ ์—†๊ฒŒ ๋””์ž์ธ ๋œ API, Delegate ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” API ์—์„œ ์–ด๋ ค์›€. ์™ธ๋ถ€ ํด๋ž˜์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ mockingํ•˜๊ณ  ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ๋œ ์˜์กด์ ์œผ๋กœ ๋งŒ๋“ค๋ฉด์„œ.

Test execution speed

    func application(_ application: UIApplication, didFinishLaunchingWithOptions opts: ...) -> Bool {
    	let isUnitTesting = ProcessInfo.processInfo.environment["IS_UNIT_TESTING"] == "1" 
    	if isUnitTesting == false {
    		// Do UI-related setup, which can be skipped when testing
    	}
    	return true
    }