نوشتن تست واحد در اندروید

چگونه میتوان برای اپلیکیشن اندروید unit test نوشت؟ بخش اول


تست های واحد (unit test) خودکار جهت کسب اطمینان از کیفیت اپلیکیشن اندروید در طولانی مدت ضروری اند و به شما کمک میکنند تا یک بخش از کد خود (مثلا یک کلاس) را تست کنید. بدین ترتیب میتوانید باگ ها و رگرسیون ها را در همان ابتدای چرخه توسعه اپلیکیشن شناسایی کنید.

در این مقاله قصد داریم شما را با نحوه نوشتن تست های واحد برای اپلیکیشن اندروید آشنا کنیم. تست های واحد دو نوع هستند:

  • تست های واحد Local : این نوع تست بر روی خود سیستم توسعه مجازی اجرا میشود، نه بر روی گوشی واقعی

  • تست های واحد Instrumented : بر روی گوشی واقعی اندروید انجام میشود

 

ساخت تست های واحد با استفاده از Junit و شبیه سازی آبجکت ها با استفاده از Mockito

کار را با ساخت تست های واحد برای اپلیکیشن اندرویدی شروع میکنیم که دو عدد را با هم جمع میکند.

این اپلیکیشن دربرگیرنده کلاس کمکی زیر میباشد

package com.testsinandroid;

import android.support.annotation.VisibleForTesting;

public class NumberAdder {

private final MainActivity mMainActivity;

public NumberAdder(MainActivity activity) {

mMainActivity = activity;

}

public void performAddition() {

double number1 = mMainActivity.getFirstNumber();

double number2 = mMainActivity.getSecondNumber();

if(!isNumberValid(number1) || !isNumberValid(number2)) {

throw new RuntimeException("invalid numbers");

}

double result = number1 + number2;

mMainActivity.setAdditionResult(result);

}

@VisibleForTesting

boolean isNumberValid(double number) {

if(number > 0) {

return true;

} else {

return false;

}

}

}

 

همچنین شامل اکتیویتی است که از کلاس استفاده میکند

package com.testsinandroid;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

public class MainActivity extends Activity {

EditText firstNumber;

EditText secondNumber;

TextView addResult;

Button btnAdd;

NumberAdder numberAdder = null;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

firstNumber = (EditText)findViewById(R.id.txtNumber1);

secondNumber = (EditText)findViewById(R.id.txtNumber2);

addResult = (TextView)findViewById(R.id.txtResult);

btnAdd = (Button)findViewById(R.id.btnAdd);

if(numberAdder == null) {

numberAdder = new NumberAdder(this);

}

btnAdd.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {

numberAdder.performAddition();

}

});

}

public double getFirstNumber() {

return Double.parseDouble(firstNumber.getText().toString());

}

public double getSecondNumber() {

return Double.parseDouble(secondNumber.getText().toString());

}

public void setAdditionResult(double result) {

addResult.setText(Double.toString(result));

}

}

 

لی اوت اکتیوتی به صورت زیر میباشد

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

<EditText

android:id="@+id/txtNumber1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:ems="2"

android:inputType="number" >

<requestFocus />

</EditText>

<EditText

android:id="@+id/txtNumber2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/txtNumber1"

android:ems="2"

android:inputType="number" >

</EditText>

<Button

android:id="@+id/btnAdd"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="46dp"

android:layout_below="@+id/txtNumber2"

android:text="Add" />

<TextView

android:id="@+id/txtResult"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/btnAdd"

android:textAppearance="?android:attr/textAppearanceMedium" />

</RelativeLayout>

 

پس از آماده شدن اپلیکیشن، دو واحد اصلی در کد داریم که باید تست شوند

  • NumberAdder : یک کلاس ساده جاوا است که MainActivity را به عنوان یک وابستگی میگیرد

  • MainActivity : اکتیویتی که UI را نمایش میدهد

 

از آنجایی که NumberAdder یک کلاس ساده است، میتوان از Junit برای تست چنین کلاس هایی استفاده کرد.

JUnit یک فریم ورک ساده برای نوشتن تست های واحد قابل تکرار میباشد. در تست یک واحد (در این شرایط NumberAdder)، سایر کلاس هایی که NumberAdder به آنها وابسته است قابل شبیه سازی میباشند.

 

Mockito یک فریم ورک بسیارخوب و مناسب برای شبیه سازی وابستگی ها در جاوا میباشد و برای افزودن JUnit و Mockito به عنوان وابستگی های تست در پروژه باید کدهای زیر را به build.gradle اضافه کنیم.

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])

compile 'com.android.support:appcompat-v7:25.0.1'

// Required -- JUnit 4 framework

testCompile 'junit:junit:4.12'

testCompile 'org.mockito:mockito-core:1.10.19'

}

 

برای نوشتن تست JUnit + Mockito برای NumberAdder یک فایل به نام NumberAdderTest.java در فولدر src/test/java/com/testsinandroid ساخته و محتوای زیر را در آن قرار دهید:

package com.testsinandroid;

import com.testsinandroid.MainActivity;

import com.testsinandroid.NumberAdder;

import org.junit.Test;

import static org.junit.Assert.assertFalse;

import static org.junit.Assert.assertTrue;

import static org.mockito.Mockito.verify;

import static org.mockito.Mockito.*;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.mockito.Mock;

import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)

public class NumberAdderTest {

@Mock

MainActivity mMockMainActivity;

@Test

public void testIsNumberValid() {

//setup

//test

NumberAdder numberAdder = new NumberAdder(mMockMainActivity);

assert(numberAdder.isNumberValid(55.0));

}

@Test

public void testIsNumberNotValid() {

//setup

//test

NumberAdder numberAdder = new NumberAdder(mMockMainActivity);

assertFalse(numberAdder.isNumberValid(-55.0));

}

@Test

public void testPerformAddition() {

//setup

when(mMockMainActivity.getFirstNumber())

.thenReturn(10.0);

when(mMockMainActivity.getSecondNumber())

.thenReturn(11.0);

//test

NumberAdder numberAdder = new NumberAdder(mMockMainActivity);

numberAdder.performAddition();

//verify

verify(mMockMainActivity).setAdditionResult(21.0);

}

}

 

کد بالا سه تست میسازد که با Test@ مشخص شده اند و با استفاده از MickitoJUnitRunner به اجرا درمی آید.

این اجراکننده یک آبجکت شبیه سازی شده را برای هر فیلدی که Mock@ دارد تزریق میکند. در تست بالا MainActivity شبیه سازی شده است. در دو تست اول بر اساس مقدار بازگشتی از تابع یک assert انجام میدهیم. در تست سوم مقادیری را که باید هنگام فراخوانی getFirstNumber و getSecondNumber بازگردانده شوند را مشخص کرده و در آخر درست بودن نتیجه را چک میکنیم.

 

پس از نوشتن تست های JUnit، میتوانیم با استفاده از کامند gradle آنها را اجرا کنیم. فرآیند بیلد شدن به موفقیت یا شکست کد در این تست ها بستگی دارد.

./gradlew test

در مطلب بعدی به سایر روش های نوشتن تست واحد میپردازیم، با ما همراه باشید.

 

https://www.sitepoint.com برگرفته از

اینها را هم بخوانید