@required

iPhone 3GS or before : 57px 

@optional
iTunesArtWork : 512px - Project에 포함시키지 않아도, App등록시 가능함.
iPhone 4 or later : 114px
Ipad : 72px

Spotlight for iPhone 3GS or before : 29px
Spotlight for iPhone 4 or later : 58px
Spotlight for iPad : 50px

iOS가 점점 지저분해진다. 
Accessibility Inspector는 iOS Simulator에서만 사용이 가능하다. 

설정(Settings) -> 일반(General) -> 손쉬운사용(Accessibility) 에서 설정 가능하다. 


Accessibility Inspector를 사용하면, 위와 같이 나오는데, 현재 Inspecting은 Disable상태이다. 
좌측의 "x" 버튼을 누르면 Inspector View가 펼쳐지면서 활성화가 된다.


Inspector 를 활성화 한 상태에서 "버튼"등의 UI Component를 터치하면, 아래와 같이 정보가 나온다. 


UIAccessibilityProtocol 에 따라 정의 된 값이 아래와 같이 나오면,
프로그래밍 적으로 지정해준적이 없는 경우에는 보통 Default가 나온다. (e.g) UILabel의 꼬리표는 UILabel의 Text가 Default다.)

Voice Over를 지원하는 App을 만들거나 Instruments를 이용한 UI Automation Script를 작성할 때, 유용하게 사용할 수 있다. 


FaceBook 채팅을 좀 전투적으로 사용해보려고 하는데, 
아무래도, Web기반 chatting은 접근성이 좋지 않다. 

그래서 외부 프로그램을 사용해보려고 하니, 

iChat으로도 가능하다. 


iChat에서 jabber type의 Account를 추가하면 바로 사용이 가능하다. 

여기서 주의 해야 할점이 account name인데, 

account name은 Facebook URL 의 앞과 같다. 

예) facebook.com/taehoonkoo -> taehoonkoo@chat.facebook.com


Preface

테스트 자동화에 대한, 필요성, 중요성은 이제 아무리 말해도 입아프다.

Instruments를 이용한 UI Test 자동화는 TDD로 사용하기에는 조금 부족하다. 
Xcode에 Integrated되어 있지 않기 때문에, Test Code와 Real Code간의 전환등이 쉽지 않고, 
Build & Run의 Step이 자동화 되어 있지 않기에 여러모로 불편함이 많다.

개발 부서에서도 당연히 사용하게 되겠지만, QA부서에서의 사용성이 더 부각 된다고나 할까,
여튼 한번 시작해보겠습니다.

UI Automation with Instruments

UIKit 기반 Application용 Test 자동화
Accessibility를 통한 UI Element 접근
Test Script로 JavaScript사용

Instruments에서는 JavaScript를 사용한다. 
JavaScript는 이해하기 쉽고, 널리 알려져 있는 Language다. 즉 그만큼 접근성이 좋다는 뜻이다.

How to automate an Application

1. Automation Template을 이용한 Trace Document 생성


Instruments Template중에 Automation Template을 사용하여 Trace Document를 생성한다. 

2. Target 설정

Target으로는 실제 Device , iOS Simulator둘다 사용할 수 있는데, 이포스트에서는 iOS Simulator를 사용한다. 


"Choose Target"을 선택하여, Test 대상이 될 Application Package(XXXX.app) 을 선택
 Target을 선택한 후 Record 버튼을 누르면 iOS Simulator가 나타남과 동시에 App이 실행된다.

이 포스트에서 사용한 Sample Project는 Apple Developer 사이트 에서 제공하는 Recipes Sample이다.


3. Recipes를 추가하는 Test Script 만들기


Script를 불러와서 Edit는 가능하지만, Create할 수 없다.
적당한곳에서 Test.js파일을 생성하고 불러 온후 "Edit"를 눌러서 Editor를 켠다.


우리가 수행할 Test Phase는 아래와 같다. 

"+" UIBarButtonItem을 터치 
Recipe Name 입력
"Done" UIBarButtonItem 터치
"Recipes" 터치
추가한 Recipe 확인

"+" UIBarButtonITem 터치하기

   UIATarget.localTarget().frontMostApp().mainWindow().navigationBar().buttons()["Add"].tap();

    app.navigationBar().withName("Add Recipe");


Recipe Name 입력

UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0].setValue(name);

"Done" UIBarButtonItem 터치

target.delay(2);

app.navigationBar().rightButton().tap();


"Recipes" 터치

    target.delay(2);

    app.navigationBar().leftButton().tap();


추가한 Recipe 확인

 app.navigationBar().withName("Recipes");

    var cell = app.mainWindow().tableViews()[0].scrollToElementWithPredicate("name beginswith '"+name+"'");

    

    if(cell.isValid() ) {

        UIALogger.logPass(testName);

    }

    else {

        UIALogger.logFail(testName);

    }


TestScript작성법은 다루지 않았는데, 다음 포스트에 할 예정이다. 


"UI Automation Reference" "Instruments User Guide" 을 참고 하면 어렵지 않게 이해할 수 있다. 


4. UI Test




5. Test Result



스크립트 로그 창에, Log Pass/Fail이 표기 된다. 






부팅시에 코드를 실행하는것은 간단합니다.

Android는 Booting시에 BOOT_COMPLETED라는 BroadCast를 생성합니다.
그걸 Catch하는 Receiver를 구현하면됩니다.

1. Permission 설명

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


2. Receiver에 IntentFilter 걸기

 <intent-filter>

                <action android:name="android.intent.action.BOOT_COMPLETED" />

 </intent-filter>


3. Receiver 구현

@Override

    public void onReceive(Context context, Intent intent) {

}



BroadcastReceiver Class를 상속받는 Receiver Class를 하나 만들고,


onReceiver Method를구현해주면 됩니다. 


참 쉽죠? ㅎㅎ



[2009-11-02 16:28:51 - Android]Android Launch!
[2009-11-02 16:28:51 - Android]adb is running normally.
[2009-11-02 16:28:51 - Android]Could not find ********.apk!

라는 녀석이 개발하다 보면 가끔 발생된다. 

이거 같은 경우는 Build 가 제대로 안되는 경우인데,

이경우 Android Project의 .classpath 파일이 꼬인 경우가 많다. 

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Android Project의 경우 일반적으로 위와 같이 되어야 하고,

Android Test Project의 경우는 아래와 같이 Dependancy가 추가 되어야한다.

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry combineaccessrules="false" kind="src" path="/SomeAndroidProject"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin"/>
</classpath>

수정하고, 나면 apk 파일이 잘 생성됨을 확인 할 수 있따. 

왜 Sprint Demo를 해야 하는 가 ?

Demo를 한다는것은 "지속적으로 완성되어 가고 있는 Product를 보여주는 것" 이다.

Project  구성원들은 이루어 낸 결과물에 만족감을 느낄 수 있다. 
만약 만족스럽지 못하다면 자극을 받을 것이다. 결국 동기 부여가 된다는 이야기다. 

Project구성원들이 Project를 확인 할 수 있다. 맡은 부분이외의 것들을 Demo를 통해 확인 할 수 있다.

Product에 대한 Feedback을 받을 수 있다. 매 Sprint 마다 피드백을 받음으로,  Product가 Agile해 질 수 있다. 
프로젝트가 산으로 가는 지 바다로 가는지 확인 할 수 있다.

점진적으로 프로젝트 완성도가 높아진다. 
Demo를 위해선 부분 기능들을 100% 완료 해야한다.  90%해놓고 나중에 하는 일이 없어진다.
왜냐하면 고객에게 보여줘야 하기 떄문이다.

Sprint Demo는 어떻게 해야 할까?

Sprint Demo는 해당 Sprint 목표에 충실한다. 
간단한 버그, 사소한 개선사항등은 구지 보여 줄 필요 없다. 
해당 목표를 명확히 프로젝트 관계자들에게 보여주면 된다. 

데모는 Presentation이 아니다. 
정교하게 보여주기 위해, 시간을 많이 들일 필요 없가 없다. 돌아가는 Product만으로 충분하다. 
기술적인 내용도 자제하고, Product가 어떻게 돌아 가는지만 보여주면 충분하다. 그것이 Point다. 


BackLog란 무엇인가 ? 



스크럼 백로그는 프로젝트 네비게이터다. 

네비게이터는 우리가 길을 떠날때, 우리가 가야할 방향, 예상 소요시간등을 제시한다.

스크럼 백로그는 해야할 일 목록, 소요 시간등을 포함한
프로젝트를 완료에 필요한 모든것들을 우리에게 보여준다.

BackLog에는 무엇을 어떻게 써야 하는가 ?

1. 형식

아이디는  Log Item에 대한 유일한 ID이며, 경우에 따라서, Issue Tracker ID와 동일 시 될 수 있다. 
BackLog의 형식은 프로젝트 의 특성, 개발팀의 성향 등에 따라, 가감하여 사용된다.

그러나, "우선순위" 와 "추정시간"을 빼버리는 일은 해서는 권장하지 않는다.
우선순위가 없다면, Scrum을 할 이유도, 할수도 없다. 

그렇다고 위의 예시 대로 따를 필요 없다.
말 그대로 Agile하게, 프로젝트별로(혹은 개발팀성향에 맞게) Customizing해서 사용하면 된다. 

2. 내용

BackLog에는 프로젝트에 수행에 필요 한 모든 내용이 기록되어야 한다. 

개발 기술, 제품의 기능만이 아니라, 개발에 필요한 모든 것들을 기록해야 한다. 
특히 개발에 걸림돌이 되는 것들은 높은 우선순위로 기록하여, 먼저 제거 하도록 해야한다.

BackLog는 누가 쓰고 관리하는가?

BackLog는 오직 Scrum Master만 이 쓰기 권한을 가진다.

Scrum Master는 고객, 외부팀, 개발팀 등의 의견을 고려하여, Project Back Log 를 작성한다.
Scrum Master만이 BackLog를 작성함으로, 얻는 이득은
커뮤니케이션 창구의 단일화다.

Scrum에서는 개발자들은 더이상 기획자들에게서 Interrupt를 받을 필요가 없다. 

BackLog는 언제 쓰는가?

최초에 BackLog는 프로젝트 시작전 , 스프린트 시작전에 작성된다.
그러나 BackLog는 항상 갱신되어야 한다. 

Sprint에 대한 BackLog를 수정하는 일은 최대한 기피하여하 하지만 
프로젝트 BackLog 는 시시때때로 갱신되어야 한다. 

Sprint에대한 Back Log은 최대한 변경을 자제해야만한다.
만약, 전반적인 수술이 필요성이 느껴진다면, Sprint를 취소하는 것을 고려해야 한다.


1. MapView 보여주기

Interface Builder 상에서, MapView를 집어 놓고, Run!! 하면 다음과 같은 에러가 난다. 


그 이유인 즉슨, MapView는 MapKit이라는 Framework에 소속되어 있고, 기본적으로 
MapKit Framework은 링크 되어 있기 때문이다. 


Add Existing Framework을 선택하여, Mapkit 을 추가 해주면. 짜잔하고 잘 나온다. 


2. Annotation Pin 노출하기

- (void)addAnnotation:(id <MKAnnotation>)annotation;


MKMapView에 addAnnotation: Method를 통해 MapView에 Annotation Pin이 표기될 Data를 추가 할 수 있다.

일단 기본적으로 제공하는 MKPlaceMark Object를 생성해서, addAnnotation 해주면, 아래와 같이 Pin이 노출된다.


3. Annotation Draggable 하도록 하기.

// If YES and the underlying id<MKAnnotation> responds to setCoordinate:, 

// the user will be able to drag this annotation view around the map.

@property (nonatomic, getter=isDraggable) BOOL draggable __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);


MKAnnotationView 의 Header를 살펴보면, draggable 이라는 변수가 있다.
여기서, 주의 할점은 addAnnotation으로 추가한 MKAnnotation을 Adopting하고 있는 Object가
setCoordinate: Message에 응답가능해야 한다는것이다.

우리는 Annotation Object를 MKPlaceMark를 이용했는데, 애석하게도 MKPlaceMark Class는 setCoordinate: Message 에 응답하지 않는다.

@interface DraggableAnnotation : MKPlacemark {


}

@property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;


@end


MKPlacemark를 상속받는 DraggableAnnotation을 정의한다. 
coordinate라는 변수는 MKPlacemark에 이미 존재 함으로 property 만 Override해준다.
그리고 ViewController에서 MKPlacemark를 사용했던 부분을 DraggableAnnotation을 사용하도록 수정한다. 

MKAnnotationView의 draggable값은 기본으로 YES이지만, MKMapView에서 내부적으로 생성하는 MKAnnotationView는 Draggable=NO이다.

MKMapViewDelegate의 Method를 하나 구현한다.

- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)annotation {

NSString *reuseIdentifier = @"abcdefg";

MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[aMapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];

if(annotationView == nil) {

annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

annotationView.draggable = YES;

annotationView.canShowCallout = YES;

}

[annotationView setAnnotation:annotation];

return annotationView;

}

 

기본적인 Pin을 보여주는 MKPinAnnotationView Object를 하나 만들고, 
draggable 을 YES로 세팅해주면, 이제 원하는대로 Pin이 Dragging된다. 

MKMapView의 구조가 UIKit이랑은 조금 달르지만, 언제나 그렇듯이 알고 나면 별것 없다. 



Daily Build라는 개념을 처음 알게 된건, 아마도,
2007년 언젠가, "조엘 온 소프트웨어"라는 책을 읽으면서 였을 껍니다.

1년차 개발자로써, "조엘 테스트" 항목에 있으니까, 그저 좋은 건가 보다 하면서,
다니고 있던 회사에 도입을 극구 주장했었습니다.

지금 생각해 보면 참 우스은 일이죠. 뭐가 어떻게 좋은건지도 제대로 이해하지 못하면서,
좋은가 보다 하면서 도입하자고 했으니 말입니다.

최근에, 이 Daily Build 라는 녀석에 대해서 다시 한번 생각해봤습니다.

" 이거 정말 필요한거야 ? " 라는 생각말입니다.

결론부터 말씀드리면,

"평생 혼자서만 개발할꺼라면 필요 없다."
그러나, 그런일은 거의 없겠죠? ^^

"소프트웨어 개발" 에 "협업"이라는 키워드가 추가되면, "Daily Build"가 힘을 발휘합니다.

우리가 협업을 하고 있다고 가정해봅시다.
거기다가, 우리의 프로젝트는 "국제적인" 프로젝트라서,
내가 퇴근하고나서야, 일을 시작하는 나라에 사는 사람과 협업을 하고 있습니다.

나는 퇴근하기전에 작업물을 Commit하고 갔는데,
재수가 없게도, Build가 깨져버렸습니다. 물론 Daily Build를 하고 있지 않으니, 나는 알턱이 없죠.

저 멀리 아주 먼 나라에서 같이 일하는 개발자는 기쁜 마음으로 출근했지만,
이런 우라질, 소스 컴파일 이 안됩니다.ㅜㅜ

그 사람은 자기가 잘 알지도 못하는 코드를 분석해가며, (거기다가 욕을 해가면서 ... )
수정하고 나서야, 자기 일을 시작하게 됩니다.

다음 날 출근한 저는 내 코드를 잘 알지도 모하는 녀석이, 기괴한 방법으로 수정했음을 발견합니다.
아.. 나는 Refactoring을 해야 겠군요 ;ㅂ;

만약, 여기에 Daily Build를 하고 있었다면 어땠을까요?

나는 퇴근하기전 Daily Build가 깨진것을 확인하고,
수정을 해놓고 나서야 퇴근합니다.

그럼 외쿡인 개발자가, 잘 알지도 모르는 소스를 분석할일도, 수정할일도 없었을테고,
내 소스를 그 사람이 자기 멋대로 수정할 일도 없었겠죠.

바로 이것입니다.

Daily Build는 빌드가 깨지는 일을 방지합니다.
CI Server를 통해 자동화 된 테스트 까지 "정상적"으로 수행시키도록 프로젝트를 꾸려가면,
S/W 가 Compilable 한 상태 뿐 아니라, "Runnable"한 상태를 유지하도록 도와줍니다.

사실 Daily Build라는 말을 사용했지만,
Commit Build, Integration Build 등등 다른 말로 표현되고 있는 "Build 자동화"에 대한 이야기입니다.

약간의 극단적인 예를 들긴했지만, 같은 사무실에 동시간대에 일하는 사람들도,
이런 자동 빌드가 없는 경우 , 빈도는 조금 적을 수 있겠지만, 여전히 같은 문제가 발생합니다.

"나는 Build 자동화를 무조건 도입해야 한다 !" 라고 생각하지 않습니다.

모바일 앱 개발 같은 경우, 혼자서 작업하는 경우도 분명히 많습니다.
그런 경우 Build 자동화는 사실 큰 의미가 없습니다.

당신의 프로젝트가 혼자서 하는게 아니라면,
"나는 무조건 빌드자동화를 도입해야 한다" 고 생각합니다.




+ Recent posts