chore: initialize repository with gitignore
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
configurations.configureEach {
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.example.task1registerform'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.example.task1registerform'
|
||||
minSdk 26
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
testOptions {
|
||||
animationsDisabled true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.core:core:1.13.1'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.5.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.5.2'
|
||||
androidTestImplementation 'androidx.test:rules:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1'
|
||||
androidTestImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package com.example.task1registerform;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.UiAutomation;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MainActivityFormTest {
|
||||
|
||||
private ActivityScenario<MainActivity> activityScenario;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
activityScenario = ActivityScenario.launch(MainActivity.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
activityScenario.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意输入框为空时,应提示完善信息并保持输入框内容不变。
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyFields_ShowIncompleteToast_AndKeepEmptyInputs() {
|
||||
onView(withId(R.id.et_name)).perform(replaceText(""), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_phone)).perform(replaceText(""), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_email)).perform(replaceText(""), closeSoftKeyboard());
|
||||
|
||||
clickAndAssertToast(R.id.btn_register, "请完善所有注册信息");
|
||||
onView(withId(R.id.et_name)).check(matches(withText("")));
|
||||
onView(withId(R.id.et_phone)).check(matches(withText("")));
|
||||
onView(withId(R.id.et_email)).check(matches(withText("")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号不满足 11 位数字规则时,应提示手机号错误并保留当前输入。
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidPhone_ShowPhoneToast_AndKeepInputs() {
|
||||
fillForm("张三", "123456", "zhangsan@example.com");
|
||||
|
||||
clickAndAssertToast(R.id.btn_register, "请输入正确的11位手机号");
|
||||
onView(withId(R.id.et_name)).check(matches(withText("张三")));
|
||||
onView(withId(R.id.et_phone)).check(matches(withText("123456")));
|
||||
onView(withId(R.id.et_email)).check(matches(withText("zhangsan@example.com")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱格式错误时,应提示邮箱错误并保留用户已经输入的数据。
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidEmail_ShowEmailToast_AndKeepInputs() {
|
||||
fillForm("李四", "13812345678", "invalid-email");
|
||||
|
||||
clickAndAssertToast(R.id.btn_register, "请输入正确的邮箱地址");
|
||||
onView(withId(R.id.et_name)).check(matches(withText("李四")));
|
||||
onView(withId(R.id.et_phone)).check(matches(withText("13812345678")));
|
||||
onView(withId(R.id.et_email)).check(matches(withText("invalid-email")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有输入均合法时,应提示注册成功并清空全部输入框。
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterSuccess_ShowSuccessToast_AndClearInputs() {
|
||||
fillForm("王五", "13912345678", "wangwu@example.com");
|
||||
|
||||
clickAndAssertToast(R.id.btn_register, "注册成功");
|
||||
onView(withId(R.id.et_name)).check(matches(withText("")));
|
||||
onView(withId(R.id.et_phone)).check(matches(withText("")));
|
||||
onView(withId(R.id.et_email)).check(matches(withText("")));
|
||||
}
|
||||
|
||||
private void fillForm(String name, String phone, String email) {
|
||||
onView(withId(R.id.et_name)).perform(replaceText(name), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_phone)).perform(replaceText(phone), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_email)).perform(replaceText(email), closeSoftKeyboard());
|
||||
}
|
||||
|
||||
private void clickAndAssertToast(int viewId, String message) {
|
||||
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||
|
||||
try {
|
||||
AccessibilityEvent event = uiAutomation.executeAndWaitForEvent(
|
||||
() -> onView(withId(viewId)).perform(click()),
|
||||
candidate -> candidate.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED
|
||||
&& containsText(candidate, message),
|
||||
5000
|
||||
);
|
||||
assertNotNull(event);
|
||||
} catch (TimeoutException exception) {
|
||||
fail("Toast not shown: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsText(AccessibilityEvent event, String message) {
|
||||
for (CharSequence text : event.getText()) {
|
||||
if (message.contentEquals(text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Task1RegisterForm">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.example.task1registerform;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Patterns;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private EditText etName;
|
||||
private EditText etPhone;
|
||||
private EditText etEmail;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
etName = findViewById(R.id.et_name);
|
||||
etPhone = findViewById(R.id.et_phone);
|
||||
etEmail = findViewById(R.id.et_email);
|
||||
Button btnRegister = findViewById(R.id.btn_register);
|
||||
|
||||
btnRegister.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
handleRegister();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleRegister() {
|
||||
String name = etName.getText().toString().trim();
|
||||
String phone = etPhone.getText().toString().trim();
|
||||
String email = etEmail.getText().toString().trim();
|
||||
|
||||
// 按实验要求顺序完成表单校验,确保 Toast 与场景一一对应。
|
||||
if (name.isEmpty() || phone.isEmpty() || email.isEmpty()) {
|
||||
showToast(R.string.toast_complete_info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!phone.matches("^\\d{11}$")) {
|
||||
showToast(R.string.toast_invalid_phone);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
|
||||
showToast(R.string.toast_invalid_email);
|
||||
return;
|
||||
}
|
||||
|
||||
showToast(R.string.toast_register_success);
|
||||
clearInputs();
|
||||
}
|
||||
|
||||
private void clearInputs() {
|
||||
etName.setText("");
|
||||
etPhone.setText("");
|
||||
etEmail.setText("");
|
||||
}
|
||||
|
||||
private void showToast(int messageResId) {
|
||||
Toast.makeText(this, getString(messageResId), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/title_register_form"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/hint_name"
|
||||
android:inputType="textPersonName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_phone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/hint_phone"
|
||||
android:inputType="phone" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:hint="@string/hint_email"
|
||||
android:inputType="textEmailAddress" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_register"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_register" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Task 1 Register Form</string>
|
||||
<string name="title_register_form">用户注册表单</string>
|
||||
<string name="hint_name">请输入姓名</string>
|
||||
<string name="hint_phone">请输入 11 位手机号</string>
|
||||
<string name="hint_email">请输入邮箱地址</string>
|
||||
<string name="action_register">提交注册</string>
|
||||
<string name="toast_complete_info">请完善所有注册信息</string>
|
||||
<string name="toast_invalid_phone">请输入正确的11位手机号</string>
|
||||
<string name="toast_invalid_email">请输入正确的邮箱地址</string>
|
||||
<string name="toast_register_success">注册成功</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.Task1RegisterForm" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
</resources>
|
||||
Reference in New Issue
Block a user