스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Xcode 핵심 기능
앱 개발 시 편집, 디버그, 커밋 등의 동작을 빠르게 반복 실행할 수 있게 해주는 Xcode의 도구 모음을 살펴보세요. 개발 워크플로 최적화 및 향상에 도움을 주는 팁과 요령도 자세히 알아볼 수 있습니다.
챕터
- 0:00 - Introduction
- 1:31 - Find the right content
- 1:45 - Filter navigators
- 3:05 - The Find navigator
- 5:43 - Move between files
- 5:47 - The tab bar
- 7:41 - The jump bar
- 8:38 - Tricks for creating new files
- 9:34 - Warnings and error annotations
- 10:42 - Using bookmarks
- 10:56 - Using Mark comments
- 11:15 - Leverage shortcuts
- 11:22 - Open Quickly
- 12:12 - Useful commands and shortcuts
- 14:19 - Code completion
- 15:10 - VIM mode
- 15:25 - Common emacs commands
- 15:43 - Get the most out of git
- 15:47 - Show the last change for a line
- 16:07 - Changes navigator
- 16:55 - Debugging
- 17:21 - Setting breakpoints
- 21:40 - Using the console
- 23:01 - Testing
- 23:51 - Test Navigator
- 26:09 - Running tests
- 27:42 - Using Test plans
- 28:38 - Code coverage
- 29:36 - Explore the Test report
- 30:23 - Distributing your app
- 30:48 - TestFlight
- 31:26 - Archiving
- 33:26 - Explore the Organizer
- 35:41 - Wrap up
리소스
- Forum: Developer Tools & Services
- Including notes for testers with a beta release of your app
- Testing
- Xcode updates
관련 비디오
WWDC24
WWDC23
WWDC22
Tech Talks
-
다운로드
안녕하세요 소프트웨어 엔지니어 여러분! 제 이름은 Myke이고 Xcode 프로젝트 매니저입니다 저는 Cheech이고 Xcode 팀의 디자이너예요 Apple SDK 베테랑이시든 Apple 플랫폼 신참 개발자이시든 여러분께 효율적인 Xcode 작업의 핵심 기능을 보여드리겠습니다 속도, 명확성, 즐거움을 모두 만끽하면서 개발 사이클을 순항할 수 있을 것입니다 우리는 매일 편집, 디버그 테스트, 커밋을 반복합니다 새 프로젝트에서는 이 사이클이 빠르고 연구도 거의 필요 없죠 하지만 프로젝트와 팀이 커지거나 새로운 팀에 합류할 때는 균형추가 이동해 문제가 생기기 시작해서 거의 절반이 문제가 됩니다 기능 추가와 버그 수정에 더 많은 연구가 필요하게 되죠 적절한 곳에서 올바른 변경을 하려면 말입니다 졸은 소식이요? Xcode에 수많은 기능이 있어서 다음으로 변경해야 할 코드를 찾는 데 도움이 됩니다 저는 편집을 더 빠르게 하는 방법을 보여드리겠습니다 다음으로 Myke가 변경한 코드 디버깅과 테스트 과정을 안내해 드리겠습니다 앱을 사용자와 공유할 준비가 되었으면 배포합니다 Xcode에는 강력한 도구를 비롯해 수많은 기능이 있습니다 이런 기능을 활용해 파일을 쉽게 이동해서 편집할 코드를 찾는 방법을 알아보겠습니다 Xcode의 가장 강력한 키 명령을 알아보고 Git을 최대한 활용하는 몇 가지 요령을 공유해 드리겠습니다 먼저 살펴볼 내용은 올바른 콘텐츠를 찾는 방법입니다 처음으로 Xcode를 열면 ‘와, 많이 진행되고 있네‘라고 마음속으로 생각할 겁니다 맞습니다 개발 사이클을 빠르게 반복하는 데 필요한 온갖 것이 이미 Xcode에 내장되어 있습니다 인터페이스 왼쪽에 있는 각 탐색기가 프로젝트를 서로 다른 관점으로 보여줍니다 이 보기에서는 프로젝트 탐색기가 선택되어 있어서 프로젝트의 파일 계층을 보여줍니다 새 파일을 만들고 코드를 작성하는 중이어서 탐색기가 혼란스러우면 먼저 폴더를 한두 개 추가한 다음 하단 막대에 파일 이름을 입력해서 파일을 찾아보세요 제가 강력한 도구 언급한 것 기억하시죠? 사실 많은 탐색기에 특수 필터가 있습니다 입력을 시작했을 때 텍스트가 이런 필터 중 하나와 일치하면 입력란 위에 메뉴 팝업이 표시되고 대상 이름을 기준으로 필터링하는 추가 기능이 제공됩니다 하단 막대 오른쪽에 표시되는 아이콘도 탐색기에 따라 변경됩니다 맨 오른쪽에 있는 아이콘을 클릭하면 Git 상태를 기준으로 파일이 필터링됩니다 따라서 다음 커밋에서 파일로 돌아가기가 쉽지만 전체 프로젝트 맥락에서 파일은 표시되어 있습니다 Xcode 커밋 문제가 있는 경우 커밋하기 전에 이 필터를 사용해 변경 내용을 쉽게 검토해 보세요 필터링은 실제로 파일 이름을 아는 경우 좋은 방법이지만 파일 이름을 기억할 수 없다면 어떻게 해야 할까요? 저는 그렇지 않을 것 같지만 그렇다고 가정해 보겠습니다 이런 상황에서는 Xcode의 Find 탐색기를 추천합니다 command-shift-F 키를 누르면 됩니다 Find 탐색기를 사용하면 전체 프로젝트에서 검색할 수 있습니다 가끔 검색에서 일치하는 결과가 몇 개 밖에 없고 그 결과만 필요한 때가 있습니다 하지만 프로젝트 전반에 나타나는 것을 검색하고 있어서 검색 결과의 범위를 좁혀야 하는 경우도 있습니다 저도 이런 일을 자주 겪습니다 다행히 Xcode가 이걸 해결해 줍니다 원하는 결과를 빠르게 찾을 때 사용할 수 있는 도구가 있죠 하단 막대를 생각하셨다면 정확하게 맞히셨습니다 프로젝트 탐색기와 마찬가지로 하단 막대를 사용해 검색 범위를 좁힐 수 있습니다 일치하는 줄에서 다른 단어를 필터링하거나 파일 이름으로 필터링해 파일에서 결과를 확인해 보세요 하지만 찾는 파일을 모르는 경우 탐색기에서 콘텐츠와 상호작용하는 좋은 방법이 있습니다 일치하는 텍스트를 살펴보기 전에 파일 이름을 훑어보려면 command 키를 누른 채 파일 이름 왼쪽에 있는 펼침 화살표를 클릭해 모든 연관 파일 목록을 접습니다 이 기능은 Xcode의 모든 개요 보기에서 작동합니다 자, 처음 세 파일의 ‘padding‘을 변경하지 않기로 했습니다 관련성 높은 파일에 집중하려고 검색에서 파일을 제거할 겁니다 먼저 파일을 선택하고 delete 키를 눌러 제거합니다 걱정하지 마세요, 방금 코드를 삭제한 것이 아닙니다 파일은 여전히 있지만 현재 쿼리에서 숨겨졌습니다 이제 관심 있는 결과에만 집중할 수 있습니다 쿼리가 제 것과 비슷하고 일치하는 결과가 많은 경우 특정 그룹의 파일에만 관심이 있다면 검색 필드 아래의 메뉴를 사용해서 검색에 집중하세요 편집 중인 파일을 포함한 어떤 그룹이든 선택 가능합니다 ‘Custom Scopes…‘를 선택하고 다른 그룹 또는 여러 그룹을 선택합니다 같은 검색 범위를 자주 사용하는 경우 저장해 두면 탐색기의 첫 메뉴에 표시됩니다 Xcode의 기호 인덱스를 필터링하세요 검색 필드 위의 ‘Text‘를 클릭해 열리는 메뉴를 사용합니다 ‘Descendant Types‘는 클래스 계층을 볼 때 좋습니다 찾기 검색 필드에 뭔가를 복사해서 붙여넣고 싶었지만 이미 복사한 중요한 정보가 지금은 사라진 걸 깨달은 적이 있습니까? 다행히도 macOS에 해결 방법이 있습니다 텍스트를 선택한 채 command-E 키를 누르세요 텍스트가 찾기 필드에 입력되고 클립보드에는 남아 있습니다 이 기능은 모든 macOS 앱에서 작동합니다 깔끔하죠? 자, 올바른 콘텐츠를 찾기 위한 필터링과 검색을 다뤘습니다 이제 파일 간에 이동하는 편리한 방법을 설명하겠습니다 먼저 탭 막대인데 소스 편집기 위쪽의 도구 막대 아래에 있습니다 탭 막대는 문서 간에 전환하는 멋진 방법입니다 오늘은 파일을 몇 개만 사용하는데도 탭 막대에 탭이 4개 열려 있습니다 왜 그럴까요? 사실 Xcode에는 2가지 유형의 탭이 있습니다 영구적 탭은 코드 편집처럼 분명한 관심을 보인 문서에 나타납니다 그리고 암시적 탭이 있는데 제가 그냥 거쳐간 파일에 대해 Xcode가 생성하는 탭입니다 암시적 탭은 파일을 나가면 사라집니다 암시적 탭에는 이탤릭체 이름이 표시되므로 다른 탭과 구별할 수 있습니다 편집하지 않고 탭을 영구적인 것으로 만들고 싶으면 빠른 메뉴에서 ‘Keep Open‘을 선택하거나 해당 탭을 이중 클릭합니다 작업을 완료하고 여러 탭을 한 번에 닫을 준비가 되셨나요? 각 탭을 개별적으로 닫는 대신 option 키를 누른 채 한 탭의 닫기 버튼을 클릭하면 다른 모든 탭이 닫힙니다 탭 막대 왼쪽에 있는 뒤로 버튼과 앞으로 버튼은 원래 기능처럼 작동합니다 하지만 하나를, 이를테면 뒤로 버튼을 길게 클릭하면 전체 기록을 볼 수 있습니다 이 기록에서 원하는 위치로 즉시 이동할 수 있습니다 버튼을 20번쯤 클릭하지 않고도 말입니다 뒤로 버튼 왼쪽에는 관련 파일 메뉴가 있는데 메뉴 이름을 보면 따로 설명이 필요 없죠 최근 파일 목록이 있고 텍스트에 따라 서로 다른 유형의 상징적 관계들이 나타납니다 현재 클래스의 서브 클래스나 현재 함수의 호출자 같은 거죠 살펴볼 모든 종류의 항목이 여기에 있습니다 탭 막대 맨 오른쪽의 버튼 3개는 편집기 UI 구성에 사용합니다 가운데 버튼은 편집기 레이아웃을 제어합니다 편집기 미니맵인 SwiftUI 미리보기와 Blame 또는 코드 적용 범위 같은 줄 액세서리 추가가 가능합니다 탐색기에 중요한 정보가 이미 표시되어서 그대로 유지하고 싶은 경우가 있습니다 앞에서 설명한 찾기 쿼리를 기억하세요? 그런데 관련 파일로 바로 이동하기를 원합니다 탭 막대를 둘러보거나 점프 막대를 사용할 수도 있겠죠 탭 막대 바로 아래에 있는 점프 막대는 현재 파일의 경로를 보여줍니다 이 경로의 모든 단계는 대화식입니다 인접한 파일을 보려면 항목을 클릭하세요 이런 목록은 길어질 수 있고 여러분도 저처럼 많은 메뉴를 탐색하다가 방향 감각을 잃을 수 있습니다 입력을 시작하면 메뉴 상단에 필터 필드가 나타나서 메뉴를 필터링할 수 있습니다 대다수 Xcode 메뉴에 이 기능이 있습니다 사용해 보세요 프로젝트 탐색기의 점프 막대에서 항목을 찾으려면 command-shift-J 키를 누릅니다 현재 파일 근처에 새 파일을 만들고 싶을 때 사용해 보세요 Xcode에는 새 파일을 만드는 방법이 굉장히 많습니다 빈 파일을 가져와서 템플릿 선택 화면을 건너뛰고 아무데나 오른쪽 클릭합니다 기존 파일의 포맷을 사용해 새 파일을 만들고 싶을 때 복사해서 붙여넣기나 복제는 고전적인 방법이죠 제가 좋아하는 방법은 option 키를 누른 채 항목을 클릭하고 드래그하여 복사하는 것입니다 저는 대개 option 키와 드래그를 사용합니다 파일이 너무 커질 수도 있겠죠 파일 일부를 잘라내 클립보드에 넣을 수 있습니다 command-X 키를 사용하면 됩니다 다음으로 탐색기에서 아무 곳이나 오른쪽 클릭합니다 option 키를 길게 누르면 메뉴 항목의 일부가 변경됩니다 ‘New file with contents of clipboard‘를 선택합니다 option 키를 길게 누르면 나타나는 대체 메뉴 옵션은 Mac의 또 다른 강력한 기능입니다 참 똑똑하죠? 또는 콘텐츠를 직접 탐색기에 붙여넣으면 Xcode가 새 파일을 만듭니다 코딩할 때 실수를 하면 물론 매우 드물겠지만요 Xcode가 해당 줄에 경고나 오류를 주석으로 표시합니다 이런 주석은 대화식입니다 보이는 것보다 정보가 많은 경우 클릭해서 열면 나머지 정보가 표시됩니다 한 줄에 2개 이상의 문제가 있는 경우 클릭해서 엽니다 짐작하셨겠지만 컴파일러에 수정 코드가 있으면 클릭해서 엽니다 ‘Fix‘를 클릭해 수정 코드를 적용합니다
코드를 작성 시 Fix-its는 구문 오류 수정안을 제시합니다 문제가 회색으로 바뀌면 문제가 새로 고쳐진 이후 파일을 변경했다는 뜻입니다 문제가 사라지면 수정된 것입니다 하지만 계속 남아 있으면요? 다시 시도해 봐야겠죠 개발자가 작업 관리를 위해 경고를 삽입할 수 있습니다 편집기에 ‘#warning‘과 함께 메시지를 입력하세요
읽지 않은 문자 메시지가 238개인 사람들에게는 어떤지 아시죠 오류 주석이 큰 도움이 될 겁니다 개인적으로 저는 깔끔한 상태를 선호합니다 책갈피는 인기 있는 수단이죠 편집기에서 아무 곳이나 오른쪽 클릭해 줄에 책갈피를 추가합니다 책갈피는 작업을 개인적으로 관리하는 멋진 방법입니다 책갈피 탐색기에서 책갈피를 지울 수 있어 더욱 좋죠 영구적인 주석을 원하신다면 파일에 MARK 주석을 추가해 보세요 이 주석은 섹션 제목으로 사용되고 미니맵과 편집기의 콘텐츠 점프 막대에 한 부분으로 나타납니다 와, 파일 간에 이동하는 방법이 정말 많네요 새로운 것을 선택하셨길 바랍니다 지금까지 키 명령을 많이 언급했지만 Xcode에는 활용할 수 있는 단축키가 훨씬 더 많습니다 Open Quickly는 Xcode에서 순간 이동에 가장 가깝습니다 A 지점과 B 지점 사이의 가장 빠른 경로죠 어디에서든 command-shift-O 키를 누른 다음 파일 이름이나 기호 이름의 일부를 입력하면 Open Quickly가 즉시 대상 목록을 제공합니다 코드 완성과 비슷한 일치하는 규칙을 사용하니까 대상 이름에 고유한 단어를 입력해서 즉시 원하는 곳으로 이동할 수 있습니다 쿼리에 슬래시를 포함하면 파일 이름 대신 파일 경로를 일치시킬 수 있습니다 쿼리를 콜론으로 끝맺고 줄 번호를 입력해 특정 줄로 이동할 수 있습니다 새로운 분할 패널에서 파일을 열고 싶을 수도 있습니다 option 키를 누른 채 return 키를 누릅니다 이제 두 파일을 나란히 볼 수 있습니다 한정자 동작을 맞춤화하려면 Xcode의 탐색 설정을 확인하세요 Xcode에는 강력한 명령이 정말 많이 있어서 새 단축키를 만들 수 있는 키가 부족할 정도죠 저는 즐겨 사용하는 단축키를 외우고 있지만 나머지 키의 경우 메뉴를 옮겨 다니는 대신 Quick Actions를 사용합니다 command-shift-A 키를 누르면 Quick Actions가 열려서 자연어로 Xcode의 명령을 검색할 수 있습니다 Xcode의 고유한 명령을 탐색하고 맞춤화하는 방법은 Xcode의 Settings 패널에서 Key Bindings 탭으로 이동하는 것입니다 우리 팀에서 go-to 명령이라고 부르는 것들이 여기에 있습니다 ‘Jump to Definition‘은 command-클릭으로 호출할 수 있고 함수 또는 유형에 대한 정의로 이동합니다 option-클릭을 사용하면 ‘빠른 도움말 보기‘로 이동해 클릭한 기호에 대한 문서를 보거나 Swift 변수에 대한 추론된 유형을 볼 수 있습니다 ‘Edit All In Scope‘는 텍스트를 선택한 채 command-control-E 키를 눌러 호출하고 현재 파일에 나오는 모든 해당 기호의 이름 변경이 가능합니다 현재 함수의 모든 호출자를 보려면 오른쪽 클릭할 때 ‘Show Callers‘를 선택합니다 함수 호출이 실행되고 있으면 ‘control-M‘ 키를 눌러 여러 줄로 다시 포맷합니다 짝을 짓는 소괄호, 중괄호 또는 따옴표의 위치를 알고 싶으세요? 한쪽을 이중 클릭하면 다른 한쪽으로 바로 이동합니다 option+화살표 키를 사용하면 단어 단위로 이동할 수 있습니다 control+화살표 키를 사용하면 하위 단어 단위로 이동합니다 Home 키와 End 키를 눌러 줄의 시작, 끝으로 이동하는 데 친숙하면 command-왼쪽 또는 오른쪽 키도 유용합니다 이런 텍스트 이동 명령은 소스 편집기의 멀티 커서 편집 기능에 필수적입니다 반복적인 switch문이나 이니셜라이저를 작성하고 똑같은 것을 여러 줄에 작성해야 합니까? control-shift 키를 길게 누른 채 여러 커서를 삽입하려는 위치를 클릭해서 여러 구문을 한 번에 작성합니다
비슷한 코드를 여러 곳에 입력해야 하는 경우 코드 완성에서 본 동일한 위치 지정자로 텍스트를 둘러싸서 템플릿을 만들 수 있습니다 Xcode의 코드 자동 완성 기능으로 코드를 완성할 수 있습니다 몇 단어만 기억할 수 있을 때도 말입니다 Xcode 16에서 자동 완성 기능은 주변 코드를 기반으로 전체 구문과 메서드를 제안해 줍니다 자동 완성 구문은 코드에 인라인으로 표시됩니다 표시된 내용을 수락하려면 tab 키를 누릅니다 전체 자동 완성 구문을 펼치려면 option 키를 길게 누릅니다 모든 것을 수락하려면 option-tab 키를 누릅니다 전문가의 팁을 드리자면 주석과 변수 이름은 자동 완성에 유용한 정보로 사용됩니다 표현력이 풍부할수록 완성 구문이 나아집니다 완성 윈도우는 작은 공간에 많은 기능이 들어 있습니다 윈도우 하단에 메서드의 전체 시그니처가 표시됩니다 완성된 구문을 선택하려면 option 키를 길게 누르고 모든 인수를 수락하려면 enter 키를 누릅니다 vim을 사용해 보신 적이 있다면 포기하기가 어렵죠 Xcode는 Editor 메뉴에서 Vim Mode를 토글하기가 쉽습니다 또한 Xcode 16은 멀티 커서 편집의 또 다른 형식으로 Vim의 반복 명령을 지원합니다 화살표 키를 사용하지 않고 줄을 옮겨 다니기도 할 겁니다 Xcode는 기본 macOS 텍스트 편집 상호작용도 모두 지원하는데 대다수 기본 emacs 명령도 지원합니다 control-A, E, P, N과 기타 많은 단축키 같은 거죠 이제 Git을 최대한 활용하는 빠른 요령을 살펴보겠습니다 오류를 수정하고 있는데 결과가 어떻게 되었는지 더 알고 싶다고 생각해 보세요 오른쪽 클릭하고 ‘Show Last Change for Line‘을 사용하세요 해당 줄에 대한 커밋 개요가 표시될 겁니다 Blame에 중점을 둔 방식이죠 문제를 야기한 사람을 찾아낼 수 있습니다 커밋하기 전에 변경 사항을 모두 검토할 준비가 되었으면 변경 사항 탐색기에서 예정된 커밋을 미리 봅니다 변경 사항을 적용하고, 커밋하고 점심을 먹으러 가기 전에 잠시 짬을 내어 진행 상황을 평가하세요 Xcode의 빠른 편집 방법을 요약해 보겠습니다 탐색기에서 콘텐츠를 필터링하고 Find 탐색기를 사용해 올바른 콘텐츠를 찾는 방법에 관해 설명했습니다 탭 막대, 점프 막대, 코드의 주석을 사용해 파일 간에 이동하는 새로운 방법을 알아보았습니다 Xcode의 많은 단축키를 활용하는 걸 잊지 마세요 Open Quickly와 Quick Actions를 활용하는 것도요 마지막으로 Git 사용 요령을 몇 가지 설명했습니다 이제 Myke에게 순서를 넘겨 디버깅에 관한 설명을 듣겠습니다 고마워요, Cheech! 디버깅은 변경할 적절한 코드를 찾는 것입니다 어떤 줄이 오작동하는지는 정확히 알 수 있지만 이유는 명확하지 않은 경우가 흔합니다 코드가 수백 번 실행되고 나서 뭔가 잘못됩니다 가끔 외견상 무해한 것 같은 버그가 훨씬 더 먼 곳에서 오류를 일으킬 수 있습니다 중단점 사용에 대한 몇 가지 멋진 요령을 보여드린 다음 print문을 작성해 더 효과적으로 디버깅하는 방법을 보여드리겠습니다 먼저, 중단점의 기능 몇 가지를 보여드리겠는데 특히 트래픽이 많은 코드에서 문제를 가려내는 데 도움이 되죠 간단한 문제인 경우 줄 번호를 클릭하기만 하면 중단점이 추가되고 프로그램이 해당 줄에 도달했을 때 멈춥니다 중단점에 너무 자주 도달해서 사실상 유용하지 않은 경우 시도할 수 있는 몇 가지 기법이 있습니다 2개의 중단점을 동시에 사용할 수 있습니다 끊임없이 실행되는 분주한 함수가 있다고 가정해 봅시다 이 함수는 앱에서 버튼을 클릭한 직후에도 실행되는데 문제가 되는 건 단 한 번의 호출입니다 버튼 핸들러에 중단점을 추가하고 분주한 함수에 중단점을 또 하나 추가합니다 분주한 함수에서 중단점을 다시 클릭해 비활성화합니다 프로그램이 실행되면 버튼 핸들러의 중단점에 도달하고 분주한 함수의 중단점을 다시 활성화한 후 계속 진행합니다 이제 적절한 상태의 트래픽이 많은 두 번째 중단점에 도달합니다 중단점 사용을 마치면 밖으로 드래그해 제거합니다 예상치 못한 오류가 있는 연산이 있어서 Swift 오류가 발생하는 경우 오류가 어디에서 발생하는지 찾기가 어려울 수 있습니다 catch 대신에 throw에서 멈출 수 있습니다 중단점 탐색기에서 ‘Swift Error Breakpoint‘를 추가하면 됩니다 앱이 오류가 발생하는 바로 그 지점에서 즉시 멈춥니다 애플리케이션에서 예상된 오류를 정기적으로 발생시키고 포착하면 이 중단점이 좀 너무 활동적일 수 있습니다 Swift 오류 중단점의 범위를 설정하기 위해 앞에서 설명한 중단점 활성화 기법 사용을 고려하세요 가끔 분주한 함수 하나에 노이즈의 흥미로운 케이스를 필터링할 충분한 정보가 있습니다 예를 들어 이 함수는 특정 연결 유형에서만 실패합니다 이 케이스에 대한 중단점에 집중할 수 있는데 편집할 중단점을 이중 클릭하고 그 연결 유형에 대한 조건을 추가하면 됩니다 이제 중단점은 그 조건이 참일 때만 멈춥니다 로깅과 함께 디버깅을 원하지만 중단한 후 log문을 삽입하고 다시 빌드해 알아내고 싶지 않을 때도 있습니다 중단점 편집기에서 중단점에 도달할 때 실행할 디버거 식을 추가할 수도 있습니다 print 표현식을 추가하고 중단점을 자동으로 계속하도록 설정합니다 이제 다시 빌드하지 않고 임시 로그를 사용할 수 있습니다
디버깅 시나리오를 설정하느라 몇 분을 보내고 겨우 한 단계 진행했다가 처음부터 전부 다시 설정해야 했던 적이 있으세요? 로깅에 사용했던 것과 동일한 디버거 명령을 사용해 프로그램이 왜 그렇게 작동했는지 알아보는 방법을 보여드리겠습니다 처음부터 다시 시작하지 않고도 근본 원인을 알 수 있습니다 예를 들어 저는 이 guard 절을 지나갈 때 함수가 실행되리라 예상했지만 그렇지 않았고 이유를 모릅니다 소급해서 표현식을 따로 떼어 그 부분을 ‘p session‘ 명령으로 디버거에서 평가하거나 guard 조건절을 평가해서 예상치 못한 반환의 원인을 찾을 수 있습니다 디버거를 수정 구슬로 사용할 수도 있는데 앞일을 예측하기 전에 이렇게 해서 스텝 인 또는 스텝 오버를 원하는지 결정합니다 녹색 프로그램 카운터를 역으로 드래그할 수도 있습니다 그러면 이전 표현식이 다시 재실행됩니다 부작용이 복구되지 않아서 프로그램이 이상해질 수 있지만 중단을 클릭하고 디버깅 세션을 다시 시작할 수밖에 없다면 사용하지 않을 이유가 없죠 시간을 꽤 절약할 수 있습니다 마지막으로 중단점이 많은 문제를 디버깅하는 중이지만 중단하지 않고 처음으로 돌아가고 싶으면 디버거 막대의 중단점 버튼을 사용해 중단점을 모두 비활성화한 후 계속하다가 중단점을 다시 활성화하고 문제를 다시 트리거합니다 때로는 같은 걸 두 번, 세 번 또는 농담 같지만 30번 디버깅해야 하는 경우도 있죠 프로그램이 충돌하면 충돌을 헤쳐 나갈 때마다 프로그램을 다시 실행해야 합니다 이런 상황은 짜증날 수 있는데 특히 몇 초 더 기다렸다가 변경하지도 않은 애플리케이션을 빌드하고 실행해야 할 때는 말이죠 command-control-R 키를 눌러서 ‘Run Without Building‘을 실행해 전체 빌드 단계를 건너뛰고 즉시 디버깅으로 돌아가세요 이런 과정은 앱 변경을 시작했지만 이전 코드를 다시 한번 디버깅하고 싶고 마지막 세션 이후 재빌드하지 않았을 때도 사용할 수 있습니다 한창 디버깅하는 중이거나 잘 모르는 코드를 디버깅할 때는 현재 위치를 파악하기가 어려울 수 있습니다 Xcode 16에서는 편집기에서 전체 백트레이스를 보고 프로젝트 전반의 함수들을 단일 편집기에 표시할 수 있습니다 따라서 현재 위치에 이르게 된 과정을 전체적으로 볼 수 있습니다 디버그 막대에서 이 보기 모드를 활성화할 수 있습니다 메모리 디버거와 보기 디버거 제어기 옆에 있죠 요즘 디버깅에 ‘print‘문을 사용하세요? 상당히 편리해서 저는 많이 사용합니다 하지만 금세 통제하기 어려워질 수 있는데 디버그 콘솔 출력을 팀 전체와 공유할 경우 특히 그렇습니다 제가 print문에 매크로를 사용한 걸 보셨을 겁니다 축약된 파일 경로를 얻기 위한 fileID나 함수 이름을 얻기 위한 function 등 이런 매크로가 여러 개 있습니다 더 많은 매크로는 설명서를 확인해 보세요 문제를 해결해 보겠습니다 print문 대신 ‘os_log‘ 사용을 고려하세요 각 메시지에 설정한 디버그 레벨을 보여줍니다 그러면 매크로가 더 이상 필요 없습니다 그리고 실행할 때 텍스트를 검색해 필터링하거나 라이브러리의 메시지만으로 필터링할 수 있습니다 메타데이터를 활성화해 오류, 정보 디버그 등의 유형, 타임스탬프와 라이브러리를 표시할 수 있습니다 로그 메시지에 더 이상 매크로가 없는 이유는 소스에서 로그 메시지를 유발한 줄로 바로 이동할 수 있기 때문입니다 이동 화살표를 클릭해서 말이죠 print문만으로는 이렇게 할 수 없습니다 디버깅에 관해 더 알아보려면 올해 진행된 ‘실행, 분석, 검사‘ 세션을 확인하세요 os_log와 함께 제공되는 모든 메타데이터와 콘솔에서 수행할 수 있는 멋진 기능을 자세히 살펴보려면 ‘구조화된 로깅으로 디버깅하기‘를 확인하세요 디버거를 알아보려면 ‘LLDB를 통한 Swift 디버깅‘을 시청하세요 이제 버그를 제거했으니 테스트에 대해 설명하겠습니다 테스트는 출시 전에 버그를 잡아내기 때문에 중요합니다 버그를 발견했을 때 테스트 케이스를 추가하면 같은 케이스가 다시 표시되지 않습니다 특히 코드베이스가 더 커지고 복잡해짐에 따라 재미있는 부분인 코드 작성을 하려면 테스트는 매우 중요합니다 프로젝트에서 모든 테스트 실행에 저는 command-U 키를 사용하죠 하지만 보통 한 번에 테스트 하나만 빠르게 반복하려고 합니다 이를 위해서 해당 테스트 함수의 마름모를 클릭합니다 테스트 모음을 테스트하려면 계층 위쪽 아무 곳이나 클릭합니다
지금까지는 테스트로 수행 가능한 작업의 시작에 불과합니다 효율적으로 테스트하는 몇 가지 기법을 자세히 살펴보겠습니다 Xcode 자체의 CI 적용 범위가 뛰어납니다 모든 pull 요청은 Xcode Cloud를 통해 실행되므로 통합되기 전에 테스트를 통과해야 합니다 테스트 탐색기, command-6 키는 모든 테스트를 표시합니다 앱의 여러 부분에 대해 테스트 계획이 여러 개 있으면 현재 계획에 있는 테스트만 표시할 수 있습니다 ‘Only Included Tests‘로 필터링하면 됩니다 테스트 모음의 크기에 따라 스크롤하는 것만으로도 적절한 테스트 실행에 충분할 것입니다 잘 작성된 훌륭한 테스트가 많으면 더 집중하고 싶어질 겁니다 제목으로 관련 테스트를 식별할 수 있으면 텍스트로 필터링할 수 있죠 Swift Testing에서는 태그별로 필터링할 수 있습니다 올바른 하위 집합을 식별했으면 선택하고 빠른 메뉴를 사용해 집중할 집합을 실행합니다 테스트를 실행하고 나면 상태가 표시됩니다 오류에 집중하려면 이에 대한 필터도 있습니다 수정한 테스트는 자동으로 목록에서 사라집니다 깔끔하게 해결된 거죠 앱을 디버깅할 때처럼 종종 테스트도 다시 실행해야 합니다 30번까지도요(31번째도 실패한 테스트는 없습니다!) 좀 전에 원래 테스트 방법을 떠나서 검색 또는 디버깅 스택 여러 개가 앱 깊숙한 곳에 남아 있을 수 있습니다 돌아가서 그 테스트 마름모를 찾아 테스트를 다시 실행하는 대신 언제든지 이전 테스트를 다시 실행할 수 있습니다 command-control-option-G 키를 사용하면 됩니다 실행과 마찬가지로 저는 종종 코드를 변경하지 않고 디버깅 세션을 다시 시작합니다 문제를 다른 관점에서 보기 위해서죠 ‘Test Without Building‘이나 command-control-U를 사용하세요 편안함을 주는 녹색 체크 표시와 의미는 분명하지만 정떨어지는 빨간색 X 외에도 Xcode에는 몇 가지 다른 테스트 상태 표시가 있습니다 사용법을 설명하겠습니다 테스트를 수정할 수 없는 경우가 있습니다 테스트 중심의 개발을 좋아하는 분이라면 API가 작동하기 전에 테스트를 작성했을 수 있습니다 이런 테스트를 예상된 오류로 표시할 수 있습니다 X가 있는 회색 아이콘으로 표시되죠 가끔 회귀가 발생했는데도 얼마간 그냥 감수하는 분들이 있습니다 저 같은 프로젝트 관리자가 그러지 말라고 하는데도 말이죠 이런 테스트는 건너뛴 것으로 표시할 수 있습니다 건너뛴 테스트는 화살표가 있는 회색 아이콘으로 표시되죠 모음에 포함된 테스트의 경우 혼합된 결과가 있을 때는 집계 상태 아이콘이 표시됩니다 모든 것을 녹색으로 돌려놓을 준비가 되었으면 이런 상태에 대해 탐색기 필터를 사용해 적절한 테스트에 집중하고 앞에서 설명한 디버깅 기법을 사용하고 출시할 준비를 마칩니다 개별 테스트 실행 방법을 이미 보여드렸지만 테스트를 실행하는 다른 방법도 많이 있습니다 대개 통과하지만 가끔 실패하는 테스트가 있는 경우 경합 상태나 다른 비결정적 동작이 발생할 수 있습니다 빠른 메뉴에서 ‘Run Repeatedly‘를 사용하세요 테스트를 고정된 횟수만큼 또는 실패할 때까지 반복 실행할 수 있습니다 테스트에 로깅 추가를 고려하세요 그러면 테스트가 끝내 실패할 때 로그를 살펴보고 이유를 알 수 있습니다 ‘xcodebuild test‘로 명령어 라인에서 테스트를 실행할 수 있습니다 스키마, 테스트 계획 또는 개별 테스트를 지정하세요 이 방법은 Git bisect 같은 도구에서 잘 작동하는데 회귀가 발생했을 떄 찾아냅니다 지속적 통합 환경에서 테스트를 실행할 준비가 되었을 때 Mac 워크로드를 줄이기 위해 개발자 계정에 Xcode Cloud가 제공되는데 월 25시간의 무료 컴퓨팅 시간이 함께 제공됩니다 특정 분기로 푸시하면 바로 작업 흐름을 구성해 클라우드에서 테스트를 시작할 수 있으며 Xcode 내에서 결과를 확인하고 테스트에 통과하면 TestFlight나 App Store Connect에 제출하도록 구성할 수도 있습니다 또한 Xcode Cloud는 안전과 보안이 보장됩니다 데이터는 암호화되고 이중 인증으로 접근 권한을 보호합니다 소스 코드는 빌드할 때만 사용되고 빌드가 완료되면 빌드 환경은 바로 파기됩니다 Xcode Cloud를 시작하려면 ‘Xcode Cloud에서의 실용적인 작업 흐름 만들기‘를 확인하세요 그런 다음 고급 팁은 ‘Xcode Cloud 최대한 활용하기‘를 시청하세요 더 나은 테스트 작성 방법을 알아보려면 ‘Xcode Cloud를 위한 빠르고 안정적인 테스트 작성‘을 보세요 테스트 계획은 원할 때 원하는 것만 실행하기 위해 테스트 그룹을 만드는 것입니다 프로젝트가 커지면 여러 다른 스키마 전체를 테스트하거나 서로 다른 테스트 그룹을 만들어 빠른 단위 테스트만 실행한 다음 그룹을 또 하나 만들어 모두 테스트한 후 커밋할 수 있습니다 바로 이때 테스트 계획이 제 역할을 합니다 각 스키마에 테스트 계획이 여럿 있을 수 있고, 그 역도 성립합니다 새 프로젝트에는 테스트 계획이 이미 생성되어 있습니다 Product > Test Plan 메뉴에서 이 테스트 계획을 편집하세요 먼저, 포함할 대상을 선택합니다 예를 들면 Unit 테스트와 UI 테스트를 모두 포함합니다 다음, 테스트 계획에 포함할 대상에서 테스트를 선택합니다 여러 스키마에 이 테스트 계획을 추가할 수도 있습니다 먼저, 스키마를 선택합니다 더하기 버튼과 ‘Add existing Test Plan…‘을 클릭합니다 Product > Test Plan에서 테스트 계획을 선택한 다음 Product > Test를 선택하거나 command-U 키를 눌러 실행합니다 코드 적용 범위나 테스트 적용 범위에 따라 테스트를 실행할 때 실행되는 코드베이스 양이 결정됩니다 문제를 발견하기 위해 테스트 작성은 중요합니다 적용 범위를 켜서 테스트 효과를 추정하고 기존 테스트에서 새 코드를 감당하는지 알 수 있으니까요 먼저, Editor 메뉴에서 ‘Code Coverage‘를 활성화합니다 그런 다음, 테스트를 실행합니다 Xcode는 이런 방식으로 적용 범위를 판단하므로 첫 번째 실행할 때까지는 결과를 얻지 못합니다 테스트가 실행되면 편집기 오른쪽에 숫자가 표시됩니다 이 숫자는 테스트 중에 해당 코드 블록이 실행된 횟수입니다 0은 코드가 실행되지 않았다는 뜻이므로 테스트에 빈틈이 있거나 앱이 코드를 전혀 실행하지 않은 것입니다 이 코드 블록은 테스트 중에 5번 실행되었습니다 모든 코드 적용 범위 개요를 볼 수도 있는데 보고서 탐색기(command-9 키)를 사용하면 됩니다 파일별로 그리고 함수별로 코드 적용 범위를 표시하므로 개선할 대상을 알 수 있습니다 Code Coverage가 표시된 탭을 테스트 보고서라고 합니다 데이터의 깊이를 보고 테스트가 어떻게 진행되고 있는지 실패했을 때 무엇이 잘못되었는지 알 수 있습니다 방금 실행한 테스트를 클릭해 무엇이 테스트되었는지 요약을 보거나 Tests 항목을 클릭해 테스트 결과를 봅니다 이 보기나 요약 보기에서 실패한 테스트를 이중 클릭해 어떤 일이 일어났는지 확인합니다 테스트가 실행된 이벤트 시퀀스와 화면 기록이 나란히 표시됩니다 이 기능은 테스트하는 동안 앱 상태를 확인할 때 엄청 유용해서 잘못된 것을 정확히 찾아낼 수 있습니다 하단의 타임라인에서는 오류가 언제 발생했는지 정확히 알 수 있습니다 Developer 앱에 테스트에 관한 훌륭한 세션이 아주 많습니다 먼저 ‘Xcode에서 앱 테스트하기‘ 문서를 읽어본 다음 올해 진행된 ‘Swift Testing 소개‘를 확인하세요 좋습니다, 이제 앱을 작성했고 버그도 모두 제거했고 테스트도 끝났으니 창작물을 세상이나 베타 테스터들에게 공개할 때가 되었네요 제품 출시가 예정되어 있으니 1.0 빌드를 사용할 때가 됐습니다 TestFlight를 사용해 베타 테스터에게 앱을 배포하는 방법 빌드한 제품을 아카이브하는 방법 내장된 Xcode Organizer를 사용해 앱에 대한 더 많은 정보를 얻는 방법을 보여드리겠습니다 앱을 출시하기 전에 베타 테스터에게 앱을 사용해 보게 하고 피드백을 받아 테스트를 다음 단계로 진행하고 싶을 것입니다 베타 테스트를 최대한 하더라도 실세계에서 사용해 보는 것이 최고죠
유료 개발자 계정에는 TestFlight가 포함되어 있어서 최대 10,000명의 베타 테스터에게 앱을 배포할 수 있습니다 이메일이나 소셜 미디어에 링크 게시로 테스터를 초대할 수 있죠 베타 테스터의 기기에 자동으로 새 버전의 앱이 다운로드됩니다 TestFlight는 모든 플랫폼에서 작동합니다 새 빌드를 게시하면 테스터에게 주요 내용을 알리는 릴리즈 노트가 포함됩니다 테스터는 피드백과 분석을 제공할 수 있으며 이런 내용은 모두 Xcode에 바로 내장됩니다 앱을 TestFlight나 App Store에 게시하면 아카이브가 시작됩니다 아카이브는 컴파일된 앱의 스냅샷인데 릴리즈 빌드를 포함하고 있습니다 릴리즈 버전은 공간을 절약하려고 최적화되어 문제 조사에 필요한 디버그 정보가 포함되어 있지 않습니다 디버그 기호는 아카이브에 포함되어서 아카이브를 저장해 두면 나중에 디버깅할 수 있습니다 또한 콘텐츠를 다시 패키징해서 선택한 대상에 상관없이 앱을 배포할 수 있습니다
빌드를 출시할 준비가 되었으면 Product 메뉴로 이동해 Archive를 선택합니다 Xcode가 앱을 한 번 더 빌드한 다음 번들로 묶어 Organizer에서 결과를 보여줍니다 작업 상태가 잘 진행될 때마다 변경 사항을 커밋하고 아카이브를 생성해서 앱을 기기에 쉽게 설치하거나 배포할 수 있는 상태로 준비하고 싶을 겁니다 아카이브를 선택한 다음 Distribute App 버튼을 클릭하세요 앱을 배포하기 위한 몇 가지 프리셋이 제시됩니다 ‘App Store Connect‘ 옵션은 앱을 TestFlight나 App Store Connect에 업로드합니다 ‘TestFlight Internal Only‘는 앱 심사를 건너뛰고 실수로 앱이 App Store에 제출되지 않도록 보호 장치를 포함합니다 콘텐츠 제공업체/조직의 베타 테스터만 이 옵션을 사용할 수 있고 외부 테스터는 사용할 수 없습니다 ‘Release Testing‘, ‘Enterprise‘ ‘Debugging‘ 옵션은 모두 포털에 등록된 기기에 사용자가 설치할 최적화된 빌드를 생성합니다 Xcode Cloud에는 TestFlight도 통합되어 있습니다 빌드하고 테스트를 통과하면 바로 TestFlight에 제출되어 테스터가 최신 빌드를 받도록 작업 흐름을 설정할 수 있습니다 Git commit 메시지에서 끌어와 테스터 메모를 자동화하는 스크립트를 구성할 수도 있습니다 TestFlight 사용법에 대한 자세한 내용은 ‘TestFlight 시작하기‘ Tech Talk 비디오를 시청하세요 테스터용 릴리즈 노트를 자동화하는 방법도 읽어보세요 ‘베타 릴리즈 앱에 테스터용 메모 포함하기‘(영문) 문서에 있습니다 Xcode Cloud의 강력한 기능을 알아보려면 작년에 진행된 ‘Xcode 및 Xcode Cloud에서 배포 간소화하기‘를 시청하세요 이제 빌드가 TestFlight에 제출되었고 테스터들이 최신 베타 버전을 실행하고 있고 사용자들이 최신 버전을 사용하고 있으니 Xcode Organizer를 자세히 살펴보겠습니다 이 Organizer (command-option-shift-O 키)에서 Xcode에 내장된 풍부한 분석 기능을 사용할 수 있습니다 물론 사용자의 개인정보는 철저히 보호됩니다 피드백과 진단을 타사 개발자들과 공유하기로 동의한 사용자들만 여기에 보고되지만 일반적으로 그들은 사용자들을 대표하는 표본임을 아실 겁니다 TestFlight 또는 App Store로 제출한 후 이 윈도우에서 수정, 디버그 테스트, 커밋할 다음 부분을 알 수 있습니다 이런 반복은 우리 소프트웨어 엔지니어의 일상적 작업입니다 그래야 고객이 앱에서 최고의 경험을 할 수 있고 우리 프로젝트 관리자도 계속 일자리를 유지할 수 있죠 추적할 기능, 수정할 버그, 해결할 회귀가 끊이지 않을 테니까요 먼저 Feedback 탭에서 다음에 구현할 기능을 알아봅시다 기능은 작업하기에 가장 재미있는 부분이죠 베타 테스터는 여기에서 피드백을 개발자와 공유할 수 있습니다 저희는 사용자들의 피드백도 듣고 싶습니다 몇몇 기능은 지금 당장 작업을 시작해야 할 것 같으니 전력투구할 목록에 추가합니다 하지만 먼저 - 여기서 제 안의 프로젝트 관리자 기질이 나오네요 해결해야 할 품질 문제가 있습니다 Organizer에 릴리즈된 제 앱 버전이 실행되는 데 시간이 너무 오래 걸린다고 나오네요 앱 실행 시 클라우드의 데이터를 동기식으로 새로 고치는 기능을 프로덕션하느라 바빠 서둘렀는데 시간만 더 있었다면 좀 더 효율적인 방식으로 작성했을 수 있었을 겁니다 그리고 최신 베타 버전에서 이상 종료 발생 횟수가 엄청나게 증가했다고 나오네요 먼저 이런 문제를 해결할 수 있도록 해당 기능 수정에 전력투구해야 할 것 같습니다 이 데이터를 살펴볼 때 사용자와 개발자의 환경은 다를 수 있다는 걸 유념하세요 개발자 기기 OS는 최신 버전이지만 사용자 기기는 아닐 수 있고 책상에서 테스트할 때는 겪지 못한 네트워크 가용성 문제가 실세계에는 있을 수 있습니다 이런 이유로 베타 프로그램을 준비해서 앱이 어떻게 작동하는지 더 많은 데이터를 수집하는 거죠 개발자, 프로젝트 관리자 제품 마케팅 파트너는 Xcode에 내장된 이 모든 정보에 자유롭게 접근해서 제품의 방향을 정할 수 있습니다 오늘 탐색, 더 빠른 편집 요령 코드 구성에 관한 세부 사항을 정말 많이 다뤘습니다 중단점을 사용해 까다로운 상황을 디버깅하는 팁과 콘솔을 수정 구슬로 사용하는 방법을 보여드렸습니다 배포하기 전에 테스트로 버그를 잡는 방법도 살펴봤습니다 테스트에서 얻은 테스트 보고서는 테스트에서 무엇을 수행했는지 기록을 보여줍니다 TestFlight를 사용해 앱을 베타 테스터에게 배포하는 방법 Organizer에서 피드백을 검토하는 방법도 설명했습니다
Cheech와 저는 여러분이 편집, 디버그, 테스트, 커밋 작업흐름 최적화 방법을 배우셨기를 바랍니다 함께해 주셔서 감사합니다 자, 버그 수정하러 갑시다!
-
-
10:26 - Warning and error annotations
#warning("This is a warning annotation") #error("This is an error annotation")
-
10:58 - Mark comments
// MARK: This is a section title
-
14:09 - Placeholder
<#placeholder#>
-
17:30 - showStarView()
showStarView()
-
17:51 - Breakpoint #1
let task = URLSession.shared.dataTask(with: cloudURL, completionHandler: handleUpdatesFromCloud)
-
17:53 - Breakpoint #2
videos = loadVideosFromCloud()
-
18:17 - Swift error breakpoint
let url = try! getVideoResourceFilePath()
-
18:34 - Swift error throw
throw URLLoadError.fileNotFound
-
18:59 - Conditional breakpoint
cloudURL.scheme == "https"
-
19:18 - Print statement in conditional breakpoint
p "Username is \(cloudURL.user())"
-
19:44 - guard clause
guard cloudURLs.allSatisfy({ $0. scheme == "https" }), session.configuration.networkServiceType == .video else { return }
-
19:56 - p session
p session
-
19:58 - p first part of guard clause
cloudURLs.allSatisfy({ $0. scheme == "https" })
-
20:02 - p second part of guard clause
p session.configuration.networkServiceType == .video
-
20:11 - Random star rating
var starRating: Int { let randomStarRating = Int.random(n: 1..<5) return randomStarRating }
-
21:16 - Converting starRatingPercentage to Int
var starRating: Int { return Int((starRatingPercentage * 5).rounded()) }
-
21:46 - print statements for debugging
var releaseDate: Date { print("🎬 Entering func \(#function) in \(#fileID)...") let currentDate = Date() let gregorianCal = Calendar(identifier: .gregorian) var components = DateComponents() components.year = releaseYear print("\(#fileID)@\(#line) \(#function): 📅 releaseYear is \(releaseYear)") if releaseYear == gregorianCal.component(.year, from: currentDate) { components.month = Int(releaseMonth) isNewRelease = true print("\(#fileID)@\(#line) \(#function): 🆕 this is a new release!") } if releaseYear < 2000 { isClassicMovie = true print("\(#fileID)@\(#line) \(#function): 🎻 this one is a classic!") } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: components)! }
-
22:09 - os_log statements for debugging
var releaseDate: Date { os_log(.debug, "🎬 Entering func \(#function) in \(#file)...") let currentDate = Date() let gregorianCal = Calendar(identifier: .gregorian) var components = DateComponents() components.year = releaseYear os_log(.info, "📅 releaseYear is \(releaseYear)") if releaseYear == gregorianCal.component(.year, from: currentDate) { components.month = Int(releaseMonth) isNewRelease = true os_log(.info, "🆕 this is a new release!") } if releaseYear < 2000 { isClassicMovie = true os_log(.info, "🎻 this one is a classic!") } let calendar = Calendar(identifier: .gregorian) return calendar.date(from: components)! }
-
23:19 - Sample unit tests
import Testing @testable import Destination_Video struct DestinationVideo_UnitTests { private var library = VideoLibrary() // Make sure starRating is returning a percentage @Test func testStarRating() async throws { for video in library.videos { #expect(video.info.starRating > 0) #expect(video.info.starRating <= 5) } } // Make sure the library loads data from the json file @Test func testLibraryLoaded() async throws { #expect(library.videos.count > 1) } }
-
24:15 - Sample UI tests
import XCTest final class Destination_VideoUITests: XCTestCase { private var app: XCUIApplication! @MainActor override func setUpWithError() throws { // UI tests must launch the application that they test. app = XCUIApplication() app.launch() // In UI tests it is usually best to stop immediately when a failure occurs. continueAfterFailure = false } @MainActor func testABeach() throws { // Tap the button to load the detail view for the "A Beach" video let aBeachButton = app.buttons["A Beach"].firstMatch aBeachButton.tap() // Make sure it has a Play Video button after going to that view let playButton = app.buttons["Play Video"] XCTAssert(playButton.exists) // Make sure the star rating for this video contains 4 stars to avoid issue we saw previously where it was only a single star because starRating was incorrectly a percentage instead of an Int let theRatingView = app.staticTexts["TheRating"] XCTAssert(theRatingView.label.contains("⭐️⭐️⭐️⭐️⭐️")) } @MainActor func testMainView() throws { // We should have at least 10 buttons for the various videos let buttons = app.buttons XCTAssert(buttons.count >= 10) // Check that the most popular videos have buttons for them for expectedVideo in ["By the Lake", "Camping in the Woods", "Ocean Breeze"] { XCTAssert(app.buttons[expectedVideo].exists) } } @MainActor func testLaunchPerformance() throws { if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { // This measures how long it takes to launch your application. measure(metrics: [XCTApplicationLaunchMetric()]) { XCUIApplication().launch() } } } }
-
24:19 - Swift Testing tags
@Test(.tags(.stars)) func testStarRating() async throws { for video in library.videos { #expect(video.info.starRating > 0) #expect(video.info.starRating <= 5) } } @Test(.tags(.library)) func testLibraryLoaded() async throws { #expect(library.videos.count > 1) } extension Tag { @Tag static var stars: Tag @Tag static var library: Tag }
-
26:35 - Running xcodebuild test from the command line
xcodebuild test -scheme DestinationVideo xcodebuild test -scheme DestinationVideo -testPlan TestAllTheThings xcodebuild test -scheme DestinationVideo -testPlan TestAllTheThings -only-testing "Destination VideoUITests/testABeach"
-
29:03 - Missing Code Coverage
func toggleUpNextState(for video: Video) { if !upNext.contains(video) { // Insert the video at the beginning of the list. upNext.insert(video, at: 0) } else { // Remove the entry with the matching identifier. upNext.removeAll(where: { $0.id == video.id }) } // Persist the Up Next state to disk. saveUpNext() }
-
29:19 - Code Coverage executed 5 times
init() { // Load all videos available in the library. videos = loadVideos() // The first time the app launches, set the last three videos as the default Up Next items. upNext = loadUpNextVideos(default: Array(videos.suffix(3))) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.