Tech/Android 개발2015.07.09 18:29

Android Studio에서 Junit 기반 단위 테스트(Unit Test) 환경 구축하기

안드로이드 Instrumentation 테스트의 경우에는 안드로이드 장치 또는 시뮬레이터에 직접 테스트 코드를 올려서 테스트가 진행됩니다. 이러한 과정 때문에 비교적 느립니다. 다른 방식으로 데스크탑 환경에서도 테스트를 할 수 있습니다. 이 방식에서는 보통 Junit을 기반으로 다양한 Mocking 라이브러리 또는 Robolectric과 같은 프레임워크를 사용하여 테스트가 진행됩니다. 이 포스트에서는 이런 방식의 가장 기본이 되는 Junit 테스트 환경을 구축하는 방법에 대해 설명하겠습니다.


진행환경

* Window 8.1  /  * Android Studio 1.2.2


1. 프로젝트 생성

Blank Activity 프로젝트를 기본 옵션으로 하나 생성합니다.


2. Unit Test 폴더 구조 생성

안드로이드에서 Instrumentation 테스트의 경우는 src/androidTest/java를, Junit 테스트의 경우에는 src/test/java를 기본 테스트 폴더로 인식합니다. 

프로젝트를 생성하시면 기본적으로 androidTest 폴더가 생성되어있을 것입니다. 상단 좌측의 프로젝트 구조 보기를 'Project'로 선택하시고 androidTest폴더에서 우클릭 -> Refactor -> Rename 을 통해 test로 이름을 변경하면 됩니다.


3. 빌드 스크립트에 Junit 추가

app의 build.gradle 파일을 열어서 dependency에 testCompile 구문을 추가합니다.

dependencies {
  ...
  testCompile 'junit:junit:4.12'
  ...
} 

메뉴에서 Tools -> Android -> Sync Project with Gradle Files 를 선택해 Gradle 파일을 Sync 시켜 줍니다.


4. Test Artifact 설정

좌측 하단 Build Variant 탭을 클릭한 후 Test Artifact를 Unit Tests로 설정해 줍니다.

여기까지 하시면 안드로이드가 java 폴더를 테스트 폴더로 인식하여 첫번째 사진과 같이 초록색 아이콘 으로 표시되어야 합니다.


5. Unit Test 코드 작성

이제 환결 설정은 다 끝났습니다! 작동하는지 알아보기 위해 간단히 Calculator 클래스를 만들어서 두 정수를 더하는 메소드를 테스트 해보겠습니다.

아래와 같이 Calculator랑 CalculatorTest 클래스를 생성하고 코드를 써줍니다.

 Calculator.java

CalculatorTest.java 

public class Calculator {
  public int add(int a, int b) {
    return a+b;
  }
}

import org.junit.Test;
import static org.junit.Assert.assertTrue;

public class CalculatorTest {
  @Test
  public void testAdd() {
    Calculator calculator = new Calculator(); 
    int actual = calculator.add(10, 10); 
    int expected  = 10+10;
    assertTrue(actual == expected);
  }
}


6. 테스트하기

테스트 java 폴더에서 우클릭 -> Run -> All Tests를 통해 테스트를 실행할 수 있습니다. 성공하면 아래와 같은 결과가 나옵니다.

끝!


참조

https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
http://tools.android.com/tech-docs/unit-testing-support


신고
Posted by 비둘기야
Tech/Android 개발2015.06.19 17:02

SignalR 이란?

웹 서버와 브라우저 간의 실시간 양방향 통신을 위해 HTML5 표준인 WebSocket이 있습니다. 그러나 아직 WebSocket이 지원되지 않는 환경이 많습니다. Signal R은 MS에서 만든, 추상화를 통해 단일한 API로 서버와 클라이언트 간의 실시간 양방향 통신을 가능하게 해주는 라이브러리입니다. 내부적으로는 환경에 따라서 WebSocket을 사용하기도 하고 Long Poliing을 사용하기도 하는 등 다양한 방식을 사용합니다. 또한, 이러한 기능을 하는 대표적인 라이브러리로는 Node.js 기반의 Socket.IO가 있습니다! 


Android에서 SignalR 사용하기

만들려고 하는 예제

  • 서버와 클라이언트 허브에 각각 'hello' 라는 메소드가 있고 이 메소드는 문자열 하나를 인자로 받습니다.
  • 안드로이드 클라이언트에서 서버에 hello 메소드를 통해 문자열을 보내면 서버도 클라이언트로 hello 메소드를 통해 같은 문자열을 보냅니다.
  • 안드로이드 앱은 서버로부터 문자열을 받으면 Toast 메시지로 이를 보여줍니다.

구현하기 

1. 라이브러리 추가
signalR 자바 및 안드로이드 버전 클라이언트 라이브러리와 gson이 필요합니다. signalR 라이브러리들은 현재 jar을 공식적으로 받을 수 있는 곳은 없고 github 저장소에서 소스를 빌드하여 사용하셔야 합니다. gson은 로컬에 jar이 없어도 jcenter나 maven 저장소의 dependency를 지정함으로써 사용할 수 있긴합니다. 일단 이 예제를 진행하면서 빌드해 놓은 라이브러리 파일들과 bintray에서 받은 gson jar 파일을 첨부합니다. 

dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.google.code.gson:gson:2.3.1' compile files('libs/signalr-client-sdk.jar') compile files('libs/signalr-client-sdk-android.jar') }


2. Permission 추가 

네트워크 통신을 사용하므로 <uses-permission android:name="android.permission.INTERNET"/> 를 Android Manifest 파일에 추가해 줍니다.


3. 멤버변수 선언

public class MainActivity extends ActionBarActivity {

    HubConnection mConnection;
    HubProxy mHub;

MainActivity.java를 생성하고 통신의 주체가 되는 모듈인 HubConnection 과 HubProxy를 선언해 줍니다. 여러 곳에서 사용되기 때문에 이번 예제에서 간편함을 위해 멤버변수로 선언하였습니다.


4. 연결 설정 및 초기화

    private void initialize() {
        String serverUrl = "http://server.url";
        String hubName = "hubName";

        Platform.loadPlatformComponent(new AndroidPlatformComponent());
        mConnection = new HubConnection(serverUrl);
        mHub = mConnection.createHubProxy(hubName);
    }

SignalR 서버 Url과 서버에서 사용하는 hubName을 설정합니다. 


5. 메시지 받을 준비 하기

    private void prepareGetMessage() {
        mHub.on("hello", new SubscriptionHandler1<String>() {
            @Override
            public void run(final String msg) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
                    }
                });
            }
        }, String.class);
    }

Hub의 on 메시지를 통해서 서버가 hello 메소드를 호출할 경우의 리스너를 등록합니다. 앞서 말씀드렸듯이 이 메소드는 인자를 하나만 받기 때문에 리스너로 SubscriptionHandler1을 사용하였습니다. 인자가 여러 개일 경우 개수에 따라서 SubscriptionHanlder2, SubscriptionHanlder3, ... 클래스를 사용하시고 알맞은 클래스 타입을 설정해주면 됩니다. 
( 안드로이드는 아직 Java8을 지원하지 않아 Lambda Expression을 사용하지 못하여 코드가 상당히 기네요ㅜㅜ ) 


6. 연결 성립하기

private void connectToServer() { try { SignalRFuture<Void> awaitConnection = mConnection.start(); awaitConnection.get(); Toast.makeText(this, "Connected", Toast.LENGTH_LONG).show(); } catch(Exception e) { Log.e("SignalR", "Failed to connect to server"); } }

동기 방식(Synchronous)으로 연결을 합니다. 따라서 Exception 없이 awaitConnect.get() 구문이 수행되고 나면 연결이 성립되었다고 볼 수 있습니다. 안드로이드에서 네트워크 통신 작업은 UI Thread에서 수행이 불가능하지만 위 메소드는 UI Thread에서도 호출이 가능합니다. 왜냐하면 실질적인 통신작업은 사실상 비동기로 이루어지고 awaitConnect.get()이 세마포어를 획득하기 위해 기다리는 식으로 구현되었기 때문입니다. 


7. 메시지 보내기

    private void sendMessage(String msg) {
        try {
            mHub.invoke("hello", msg).get();
        } catch( Exception e ){
            Log.e("SignalR", "Fail to send message");
        }
    }

Hub의 invoke 메소드를 통해 서버 Hub 메소드를 호출하는 식으로 메시지를 보냅니다. 이 역시 연결 성립할 때와 같은 방식으로 동기로 진행되며 UI Thread에서도 사용 가능합니다.


8. 연결 해지

    @Override
    protected void onDestroy() {
        mConnection.stop();
        super.onDestroy();
    }

stop 메소드를 통해 연결을 해지합니다. 이 예제에서는 앱의 onDestory가 호출 될 때 연결 해지를 하였습니다! 


9. 최종 결과 앱


지금까지 말씀드린 내용을 구현한 소스파일을 첨부합니다.

activity_main.xml

MainActivity.java


참조

Github : SignalR/java-client

Github : SignalR/java-samples

Getting Started with the Java SignalR SDK



신고
Posted by 비둘기야

티스토리 툴바