【问题标题】:Android Unit Test startAndroid 单元测试开始
【发布时间】:2016-07-18 12:31:37
【问题描述】:

我已经阅读了很多文章并尝试使用 Roboelectric 开始单元测试,但我仍然不明白,也无法编写简单的单元测试。 任何人都可以指导我使用什么以及如何开始,因为在 android 中进行单元测试并不容易。

【问题讨论】:

  • 你查看过他们的网站教程吗?
  • @Lawrance 是的,我检查了网站教程,但仍然无法有一个清晰的想法
  • @MiguelBenitez 我检查了这个链接,它非常有限,我需要书之类的东西
  • 使用robotium代替roboelectric有什么问题吗?

标签: android unit-testing testing


【解决方案1】:

我也遇到了同样的问题,就像我在 android 中获得单元测试模块之前一样。这是一个可能对您有所帮助的简单示例。我已尽力帮助您。您只需运行 EmailValidatorTest 类即可查看测试结果。对于 assert(JUnit),您可以关注 Assert。这是 XML。

<LinearLayout 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:background="#F0F0F0"
android:orientation="vertical" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:text="@string/lbl_register"
    android:textAllCaps="true"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:textColor="#176CEC"
    android:textStyle="bold" />

<EditText
    android:id="@+id/editText_email"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#fff"
    android:ems="10"
    android:hint="@string/lbl_email_hint"
    android:inputType="textEmailAddress"
    android:padding="12dp" />

<EditText
    android:id="@+id/editText_password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="1dp"
    android:background="#fff"
    android:ems="10"
    android:hint="@string/lbl_password_hint"
    android:inputType="textPassword"
    android:padding="12dp" />

<Button
    android:id="@+id/btn_signup"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="20dp"
    android:background="#176CEC"
    android:text="@string/lbl_btn_signup"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:textColor="#fff"
    android:textStyle="bold" />

这是我的 MainActivity

package com.example.hassidiczaddic.unittesting;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.hassidiczaddic.unittesting.R;
public class MainActivity extends Activity {
private EditText emailEditText;
private EditText passEditText;
private Button btnsignup;
private EmailValidator mEmailValidator;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    emailEditText = (EditText) findViewById(R.id.editText_email);
    passEditText = (EditText) findViewById(R.id.editText_password);
    // Setup field validators.
    mEmailValidator = new EmailValidator();
    emailEditText.addTextChangedListener(mEmailValidator);
    passEditText.addTextChangedListener(mEmailValidator);


btnsignup=(Button)findViewById(R.id.btn_signup);
    btnsignup.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {


            // Don't save if the fields do not validate.
            if (!mEmailValidator.isValid()) {
                emailEditText.setError("Invalid email or Password");
                Log.w("TAG", "Invalid email");
                return;
            }else
                Toast.makeText(MainActivity.this,"Satrun is dead",Toast.LENGTH_SHORT).show();
        }
    });




}

}

这是我的 EmailValidator 类

package com.example.hassidiczaddic.unittesting;
import android.app.Activity;
import android.text.Editable;
import android.text.TextWatcher;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EmailValidator implements TextWatcher {

/**
 * Email validation pattern.
 */
// validating email id
public static final Pattern EMAIL_PATTERN = Pattern.compile(
        "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
                "\\@" +
                "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
                "(" +
                "\\." +
                "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
                ")+"
);

// validating password with retype password
private boolean isValidPassword(String pass) {
    if (pass != null && pass.length() > 6) {
        return true;
    }
    return false;
}

private boolean mIsValid = false;

public boolean isValid() {
    return mIsValid;
}

public static boolean isValidEmail(CharSequence email) {
    return email != null && EMAIL_PATTERN.matcher(email).matches();
}

public static boolean isValidPassword(CharSequence pass) {
    return pass != null && isValidPassword(pass);
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void afterTextChanged(Editable editableText) {
 mIsValid=isValidEmail(editableText);
    mIsValid=isValidPassword(editableText);
}
}

这是我在 android 中的单元测试:

package com.example.hassidiczaddic.unittesting;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
import static org.junit.Assert.*;
@SmallTest
public class EmailValidatorTest {
@Test
public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name_@email.com"));
}

@Test
public void emailValidator_CorrectEmailSubDomain_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.co.uk"));
}

@Test
public void emailValidator_InvalidEmailNoTld_ReturnsFalse() {
    assertFalse(EmailValidator.isValidEmail("name@email"));
}

@Test
public void emailValidator_InvalidEmailDoubleDot_ReturnsFalse() {
    assertFalse(EmailValidator.isValidEmail("name@email..com"));
}

@Test
public void emailValidator_InvalidEmailNoUsername_ReturnsFalse() {
    assertFalse(EmailValidator.isValidEmail("@email.com"));
}

@Test
public void emailValidator_EmptyString_ReturnsFalse() {
    assertFalse(EmailValidator.isValidEmail(""));
}

@Test
public void emailValidator_NullEmail_ReturnsFalse() {
    assertFalse(EmailValidator.isValidEmail(null));
}


@Test
public void passwordValidator_NullPassword_ReturnsFalse(){
    assertFalse(EmailValidator.isValidPassword(null));

    //other testcases for passwords
}}

不要忘记 syc 你的 Gradle:

// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'

【讨论】:

  • 很高兴能提供帮助。我遇到了和您类似的问题,但无处找到解决方案。如果我熟悉这些主题,我会随时提供帮助。如果您认为这确实有助于您理解,请将答案标记为正确。 :) :)
  • 您好,感谢您的努力,但我已经在您回答之前接受了上面的答案,所以我只能投票给您的答案
【解决方案2】:

要使用robotium,请按照以下步骤操作:

1.- 导入robotium - Build.gradle:

dependencies {
    ....
    testCompile 'junit:junit:4.12'
    .....
    compile 'com.jayway.android.robotium:robotium-solo:5.6.0'
    compile 'com.android.support:support-annotations:23.0.0'
    .....
}

2.- 创建一个抽象类来在 androidTest 包中初始化你的测试:

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;

import com.robotium.solo.Solo;


public abstract class AbstractSystemTestBase<T extends Activity> extends ActivityInstrumentationTestCase2<T> {

    public static final int WAIT_FOR_ACTIVITY_TIMEOUT = 30000;  
    public static final int WAIT_FOR_DIALOG_TIMEOUT = 30000;    
    public static final int WAIT_FOR_VIEW_TIMEOUT = 6000;   
    public static final int WAIT_FOR_TEXT_TIMEOUT = 6000;   
    public static final int STANDARD_WAIT_TIME = 30000;
    public static final int SHORT_WAIT_TIME = 5000;

    protected Solo solo;

    public AbstractSystemTestBase(Class<T> activityClass) {
        super(activityClass);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        solo = new Solo(getInstrumentation(), getActivity());
    }

    @Override
    public void tearDown() throws Exception {
        super.tearDown();
        solo.finishOpenedActivities();
    }


}

3.- 创建扩展抽象类的测试类(在 androidTest 包内):

public class TestMainMenu extends AbstractSystemTestBase<MainMenuActivity> {

    public TestMainMenu() {
        super(MainMenuActivity.class);
    }

    public void testMenu() throws InterruptedException {
        assertTrue("MainMenu Activity never started", solo.waitForActivity(MainMenuActivity.class, WAIT_FOR_ACTIVITY_TIMEOUT));
        //YOUR TESTS HERE

        //EXAMPLE:

         View view = solo.getView("main_menu_activity_iv_go_activity_one");
        solo.clickOnView(view);
        assertTrue("Activity one never started", solo.waitForActivity(Activity1.class, WAIT_FOR_ACTIVITY_TIMEOUT));


    }
}

4.- 运行测试。右键单击您的测试类

【讨论】:

  • 你能举个例子如何测试我在某个类中编写的方法吗?
  • 取决于方法的作用。在您有一个具有除法方法的 Math 类的情况下,此代码有效: SimpleMath mSimpleMath = new SimpleMath(); int 结果 = mSimpleMath.divide(4,2); assertTrue("结果失败!", result==2);尽管我认为在这种情况下使用 JUnit 更好
  • 关于接受一些参数并返回一个对象的排序方法。我的意思是我如何从测试中引用我想要测试的指定方法
  • 这个方法在你正在测试的activity中吗?
  • 调用getActivity()可以得到activity;或 solo.getCurrentActivity();取决于您是在开始测试的活动中还是在其他活动中。对您的 Activity 类进行强制转换,调用该方法并检查结果。
【解决方案3】:

你可以试试 Mockito。

使用 Mockito 进行 Android 单元测试 https://www.raywenderlich.com/174137/android-unit-testing-with-mockito

使用 TestMe(用于 Android Studio 的 IntelliJ 插件可以非常轻松地生成单元测试代码)

TestMe (https://plugins.jetbrains.com/plugin/9471-testme)

为 Java 或 Groovy 中的源类自动生成单元测试。 没有更多样板!

特点:

  • 使用 JUnit 4/5、TestNG 或 Spock 框架自动生成 Java 或 Groovy 测试代码
  • 自动生成 Mockito 模拟
  • 生成测试参数和断言语句

快速入门: http://weirddev.com/testme/

【讨论】:

    猜你喜欢
    • 2010-11-20
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多