Robolectric เป็นเฟรมเวิร์กสำหรับการทดสอบหน่วยของแอปพลิเคชัน Android ที่ช่วยให้เรียกใช้การทดสอบได้โดยตรงบน JVM โดยไม่ต้องใช้โปรแกรมจำลองหรืออุปกรณ์จริง มันสกัดกั้นการเรียกของ Android SDK และให้วัตถุเงา (shadow-objects) ที่จำลองพฤติกรรมของส่วนประกอบจริง ตาม Robolectric Documentation, 2025 วัตถุเงาแทนที่คลาส Android API ประมาณ 15,000 คลาส ทำให้การทดสอบแยกออกจากแพลตฟอร์ม
ประเด็นสำคัญ
Robolectric เป็นเฟรมเวิร์กโอเพนซอร์สที่สร้างขึ้นในปี 2010 เพื่อเร่งการทดสอบแอปพลิเคชัน Android แทนที่จะทำงานบนโปรแกรมจำลองหรืออุปกรณ์ Robolectric มอบการใช้งานเงาของคลาส Android SDK ที่ทำงานโดยตรงบนเครื่องเสมือน Java (JVM) ซึ่งช่วยให้เรียกใช้การทดสอบนับพันรายการได้ภายในไม่กี่วินาที
การทดสอบ Android แบบดั้งเดิมต้องเรียกใช้แอปพลิเคชันบนโปรแกรมจำลอง ซึ่งใช้เวลา 3–10 นาทีในการสร้าง APK ติดตั้ง และเริ่มต้น Robolectric ขจัดขั้นตอนนี้: การทดสอบจะถูกคอมไพล์เป็นการทดสอบ Java/Kotlin ปกติและเรียกใช้ผ่าน JUnit ซึ่งให้รอบการตอบกลับภายในไม่กี่วินาทีแทนที่จะเป็นนาที
Robolectric รองรับทุกเวอร์ชัน Android ตั้งแต่ API 16 (Android 4.1) จนถึงรุ่นเสถียรล่าสุด สำหรับแต่ละเวอร์ชันจะมีชุดวัตถุเงาที่เกี่ยวข้องซึ่งจำลองพฤติกรรมของเวอร์ชันแพลตฟอร์มที่กำลังทดสอบแอปพลิเคชัน
สถาปัตยกรรมของ Robolectric อาศัยกลไกการสกัดกั้นการเรียกผ่านการแทนที่ตัวโหลดคลาส เมื่อการทดสอบเรียกเมธอด Android SDK Robolectric จะสกัดกั้นการเรียกและส่งต่อไปยังวัตถุเงา วัตถุเงาคือคลาส Java ที่เลียนแบบพฤติกรรมจริงของส่วนประกอบ Android แต่ทำงานโดยไม่มีแพลตฟอร์มดั้งเดิม
วัตถุเงาใช้เมธอดหลักของคลาส Android ดั้งเดิม ตัวอย่างเช่น ShadowTextView เลียนแบบเมธอดเช่น getText(), setText(), getCurrentTextColor() และอื่น ๆ เมื่อเรียก textView.setText("สวัสดี") เงาจะบันทึกสตริงและส่งคืนเมื่อเรียก getText() สิ่งนี้แยกการทดสอบจากการเรนเดอร์จริงและบริการของระบบ
Robolectric รองรับคลาสเงามากกว่า 200 คลาสที่ครอบคลุมส่วนประกอบหลักของ Android SDK: Activity, Fragment, TextView, Button, RecyclerView, WebView, LocationManager, ConnectivityManager และอื่น ๆ อีกมากมาย วัตถุเงาทำตามลำดับชั้นการสืบทอดเดียวกันกับคลาส Android ดั้งเดิม
การติดตั้ง Robolectric ในโปรเจกต์ Gradle ต้องเพิ่มการพึ่งพา testImplementation "org.robolectric:robolectric:4.x" นอกจากนี้ยังต้องระบุการกำหนดค่าandroidsdk ในไฟล์ build.gradle และเพิ่มความละเอียด android:testInstrumentationRunner ไม่จำเป็นต้องใช้ปลั๊กอินการทดสอบ Android เพื่อทำงานกับ Robolectric
หลังจากเพิ่มการพึ่งพา ต้องกำหนดค่าไดเรกทอรีสำหรับ manifset ทรัพยากรและสินทรัพย์ Robolectric จะค้นหา AndroidManifest.xml โดยอัตโนมัติ แต่อาจต้องระบุเส้นทางด้วยตนเองผ่านคำอธิบายประกอบ@Config หรือคุณสมบัติของระบบ สำหรับโปรเจกต์หลายโมดูล การกำหนดค่าจะถูกตั้งค่าแยกกันสำหรับแต่ละโมดูล
// build.gradle — การกำหนดค่า Robolectric
android {
testOptions {
unitTests.includeAndroidResources = true
unitTests.all {
systemProperty 'robolectric.dependency.dir',
project.rootDir.absolutePath + '/build/intermediates'
}
}
}
dependencies {
testImplementation 'org.robolectric:robolectric:4.13'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
คำอธิบายประกอบ@Config อนุญาตให้แทนที่พารามิเตอร์การทดสอบ: sdk (เวอร์ชัน API), manifest (เส้นทางไปยัง manifset), qualifiers (การกำหนดค่าหน้าจอ, ภาษา) สิ่งนี้มีประโยชน์สำหรับการทดสอบพฤติกรรมของแอปพลิเคชันบนเวอร์ชัน Android ที่แตกต่างกัน การวางแนวหน้าจอ และการแปลภาษา
การทดสอบ Robolectric เขียนเป็นการทดสอบหน่วยปกติด้วย @RunWith(RobolectricTestRunner.class) สำหรับ JUnit 4 หรือผ่าน RobolectricExtension สำหรับ JUnit 5 ActivityController จัดการวงจรชีวิตของ Activity: create(), start(), resume(), pause(), stop(), destroy() ซึ่งช่วยให้ทดสอบการเปลี่ยนสถานะแต่ละครั้งโดยละเอียด
ในการทดสอบ Activity ให้ใช้ ActivityController ซึ่งจะผ่านขั้นตอนวงจรชีวิตตามลำดับ การเข้าถึง Activity ทำได้ผ่าน controller.get() ส่วนประกอบมุมมองทั้งหมดเข้าถึงได้ผ่าน findViewById เช่นเดียวกับในแอปพลิเคชันจริง วัตถุเงาช่วยให้ตรวจสอบข้อความ การมองเห็น สี และคุณลักษณะอื่น ๆ ของมุมมอง
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.SDK_INT)
public class MainActivityTest {
@Test
public void testActivityDisplaysGreeting() {
ActivityController<MainActivity> controller =
Robolectric.buildActivity(MainActivity.class);
controller.create().start().resume();
MainActivity activity = controller.get();
TextView greeting = activity.findViewById(R.id.greeting);
ShadowTextView shadow = Shadows.shadowOf(greeting);
assertEquals("Welcome!", shadow.getText());
}
}
Robolectric สกัดกั้นการเรียก startActivity() และอนุญาตให้ตรวจสอบ intent ที่ส่งผ่าน ShadowActivity ซึ่งทำให้สามารถทดสอบการนำทาง: ตรวจสอบว่าเมื่อคลิกปุ่ม Intent ถูกส่งด้วย Action, Data และพารามิเตอร์ Extra ที่ถูกต้อง
@Test
public void testNavigationToDetails() {
controller.create().start().resume();
MainActivity activity = controller.get();
activity.findViewById(R.id.detailsButton).performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
Intent intent = shadowActivity.getNextStartedActivity();
assertEquals(
DetailsActivity.class.getName(),
intent.getComponent().getClassName()
);
}
Robolectric และโปรแกรมจำลองแก้ปัญหางานที่แตกต่างกัน Robolectric เหมาะสำหรับการทดสอบหน่วยที่รวดเร็ว การตรวจสอบตรรกะ UI ส่วนประกอบทางธุรกิจและพื้นที่เก็บข้อมูล โปรแกรมจำลองจำเป็นสำหรับการทดสอบเครื่องมือ การตรวจสอบการรวมกับ API การทดสอบกล้อง เซ็นเซอร์ และประสิทธิภาพ
| คุณลักษณะ | Robolectric | โปรแกรมจำลอง |
|---|---|---|
| ความเร็ว | ~5 วินาทีต่อ 100 การทดสอบ | ~5 นาทีต่อ 100 การทดสอบ |
| การเริ่มต้น | ไม่ต้องสร้าง APK | ต้องสร้าง APK |
| API จริง | การจำลองแบบเงา | Android SDK ดั้งเดิม |
| พร้อมใช้งานทันที | JUnit เท่านั้น | เฟรมเวิร์กใด ๆ |
Robolectric เหมาะอย่างยิ่งสำหรับการทดสอบ ViewModel, Repository และ UseCase — ส่วนประกอบที่ใช้ Android SDK แต่ไม่ต้องการ UI จริง ViewModel ถูกทดสอบผ่านการทดสอบ JUnit ปกติด้วย RobolectricExtension ในขณะที่ส่วนประกอบวงจรชีวิต (LiveData, StateFlow) ทำงานในสภาพแวดล้อมเงาโดยไม่ต้องใช้ mock
Robolectric รองรับ LiveData ทันที: คุณสามารถสมัครรับ LiveData ในการทดสอบ เปลี่ยนสถานะผ่าน ViewModel และตรวจสอบค่าที่ส่งออก สำหรับการทำงานแบบอะซิงโครนัส จะใช้ InstantTaskExecutorRule หรือ runBlocking สำหรับ coroutine ซึ่งช่วยลดความจำเป็นในการจำลองส่วนประกอบทางสถาปัตยกรรม
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [BuildConfig.SDK_INT])
class ProfileViewModelTest {
private val repository = FakeUserRepository()
private val viewModel = ProfileViewModel(repository)
@Test
fun `loading profile sets state to success`() = runBlocking {
viewModel.loadProfile("user123")
val state = viewModel.profileState.getOrAwaitValue()
Assertions.assertTrue(state is UiState.Success)
}
}
หากวัตถุเงามาตรฐานของ Robolectric ไม่ครอบคลุมคลาส Android SDK ที่ต้องการ คุณสามารถสร้างเงาที่กำหนดเองได้ โดยสร้างคลาสด้วยคำอธิบายประกอบ @Implements(ClassName.class) และใช้เมธอดที่ต้องการด้วย @Implementation เงาที่กำหนดเองจะถูกลงทะเบียนผ่าน @Config(shadows = [CustomShadow::class])
Robolectric รองรับการทดสอบ ContentProvider ผ่าน Robolectric.buildContentProvider() คุณสามารถตรวจสอบการดำเนินการ CRUD, การสอบถามด้วยการจับคู่ URI และการจัดการสิทธิ์การเข้าถึง ทรัพยากร (สตริง สี ขนาด) ยังเข้าถึงได้ผ่าน RuntimeEnvironment.application.resources ซึ่งช่วยให้ทดสอบโค้ดที่ขึ้นอยู่กับทรัพยากร
การเปลี่ยนจากการทดสอบเครื่องมือไปยัง Robolectric ต้องการการเปลี่ยนแปลงแนวทาง การทดสอบเครื่องมือ (AndroidJUnit4) ตรวจสอบพฤติกรรมจริงบนโปรแกรมจำลอง ในขณะที่ Robolectric ตรวจสอบตรรกะที่แยกออกมาในสภาพแวดล้อมเงา แนะนำให้ครอบคลุมตรรกะทางธุรกิจด้วยการทดสอบ Robolectric และปล่อยให้การทดสอบเครื่องมือสำหรับสถานการณ์การรวม
เมื่อย้าย ต้อง: แทนที่ AndroidJUnit4 ด้วย RobolectricTestRunner, เพิ่ม @Config ด้วยเวอร์ชัน SDK เป้าหมาย, แทนที่ ActivityTestRule ด้วย ActivityController และย้ายการพึ่งพาจาก androidTestImplementation ไปยัง testImplementation Mock (MockK, Mockito) ทำงานกับ Robolectric โดยไม่มีการเปลี่ยนแปลง — ไม่ขึ้นกับแพลตฟอร์ม
Robolectric ไม่รองรับ: การทดสอบกล้อง (CameraX), NFC, Bluetooth, การตรวจสอบไบโอเมตริก, การทำงานกับไฟล์จริงและไลบรารีดั้งเดิม สถานการณ์เหล่านี้ต้องการการทดสอบเครื่องมือบนโปรแกรมจำลอง Robolectric ไม่สร้างการเรนเดอร์จริงขึ้นมาใหม่เช่นกัน — การทดสอบเลย์เอาต์ควรทำผ่าน Compose Test Rule หรือ Espresso อย่างไรก็ตาม สำหรับการตรวจสอบตรรกะทางธุรกิจ การนำทาง และสถานะ ViewModel Robolectric แทนที่โปรแกรมจำลองอย่างสมบูรณ์ด้วยความเร็วที่เร็วกว่า 10 เท่า
Robolectric ต้องการ JDK 11 ขึ้นไปและเข้ากันได้กับ AGP (Android Gradle Plugin) ตั้งแต่ 7.0 จนถึงเวอร์ชันเสถียรล่าสุด ตัวจัดการ SDK ของ Robolectric ดาวน์โหลดเวอร์ชัน Android API ที่จำเป็นโดยอัตโนมัติเมื่อเรียกใช้ครั้งแรก — เป็นการดำเนินการครั้งเดียว สำหรับเซิร์ฟเวอร์ CI แนะนำให้โหลด SDK ล่วงหน้าผ่าน sdkmanager เพื่อหลีกเลี่ยงความล่าช้าในการเรียกใช้การทดสอบครั้งแรก การอัปเดต Robolectric เป็นเวอร์ชันใหม่มักไม่ต้องการการเปลี่ยนแปลงโค้ดทดสอบ เพียงอัปเดตหมายเลขการพึ่งพาใน build.gradle
Robolectric เข้ากันได้กับเฟรมเวิร์กการจำลองยอดนิยม: MockK สำหรับ Kotlin และ Mockito สำหรับ Java Mock ใช้สำหรับแยกการพึ่งพา: ที่เก็บข้อมูล, ไคลเอ็นต์ API, SharedPreferences กฎหลักคือไม่จำลองคลาส Android SDK — มีวัตถุเงาสำหรับสิ่งนั้น จำลองเฉพาะเลเยอร์แอปพลิเคชัน: UseCase, Repository, DataSource และส่วนประกอบตรรกะทางธุรกิจอื่น ๆ การรวมกันของวัตถุเงาและ mock นี้ให้ความยืดหยุ่นสูงสุดด้วยความพยายามในการเขียนทดสอบน้อยที่สุด
คำถามที่พบบ่อย
Espresso เป็นเฟรมเวิร์กเครื่องมือที่ทำงานบนโปรแกรมจำลองหรืออุปกรณ์ Robolectric เป็นเฟรมเวิร์กการทดสอบหน่วยที่ทำงานบน JVM Espresso ทดสอบพฤติกรรมจริง Robolectric ทดสอบตรรกะที่แยกออกมาในสภาพแวดล้อมเงา ทั้งสองเสริมซึ่งกันและกัน
ได้ Robolectric รองรับ Jetpack Compose ตั้งแต่เวอร์ชัน 4.8 การทดสอบส่วนประกอบ Compose ดำเนินการด้วย ComposeTestRule คล้ายกับโปรแกรมจำลอง อย่างไรก็ตาม การทดสอบ Compose บน Robolectric ไม่ตรวจสอบการเรนเดอร์จริง — เฉพาะตรรกะการประกอบ
Robolectric รองรับโปรเจกต์หลายโมดูล แต่ละโมดูลถูกกำหนดค่าแยกต่างหากด้วย manifset และทรัพยากรของตัวเอง สำหรับโมดูลที่ไม่มีส่วนประกอบ UI โมดูลไลบรารีที่ไม่มีปลั๊กอิน Android ก็เพียงพอ ในโปรเจกต์ขนาดใหญ่ที่มีหลายสิบโมดูล การทดสอบ Robolectric ของแต่ละโมดูลทำงานแบบขนาน ซึ่งให้ข้อได้เปรียบด้านความเร็วเพิ่มเติมเมื่อเทียบกับการทำงานตามลำดับบนโปรแกรมจำลอง
ปัญหาทรัพยากรเกิดขึ้นหากใน build.gradle ไม่มี unitTests.includeAndroidResources = true หรือขาดคำอธิบายประกอบ @Config ที่มีเส้นทางที่ถูกต้องไปยัง manifset Robolectric ใช้ทรัพยากรที่คอมไพล์แล้วจาก build/intermediates
การทดสอบ Robolectric จะถูกดีบักเหมือนการทดสอบ Java/Kotlin ทั่วไปใน Android Studio มีจุดเบรก, การดีบักทีละขั้นตอน, การตรวจสอบวัตถุเงาและสถานะของมัน การบันทึกเปิดใช้งานผ่าน -Drobolectric.logging=debug ในตัวเลือก VM
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม