narjes Mansoori
narjes Mansoori
خواندن ۴ دقیقه·۸ ماه پیش

آموزش تست نویسی در اندروید(ادامه)

  1. خب Before@: این آنوتیشن برای مشخص کردن یک متدی است که قبل از اجرای هر تست اجرا میشود. معمولاً برای تنظیمات مورد نیاز قبل از هر تست استفاده میشود.
public class ExampleTest {
private Calculator calculator;
@Before
public void setUp() {
calculator = new Calculator();
}
@Test
public void testAddition() {
// کد تست }
}
  1. انوتیشن After@: این آنوتیشن برای مشخص کردن یک متدی است که بعد از اجرای هر تست اجرا میشود. معمولاً برای پاکسازی وضعیت بعد از هر تست استفاده میشود.
public class ExampleTest {
private DatabaseManager databaseManager;
@After
public void tearDown() {
databaseManager.closeConnection();
}
@Test
public void testDatabaseConnection() {
// کد تست
}
}

حالا BeforeClass@و AfterClass@ چی هستند:مشابه Before و After هستند، اما متدهایی که با این Annotationها مشخص میشوند، قبل و بعد از اجرای همه تستها در یک کلاس اجرا میشوند.


class MyTestClass {

companion object {

@BeforeClass
@JvmStatic
fun setUpClass() {
// تنظیمات قبل از اجرای همه تستها
println("Setting up before all tests...")
}

@AfterClass
@JvmStatic
fun tearDownClass() {
// پاکسازی بعد از اجرای همه تستها
println("Tearing down after all tests...")
}
}

@Test
fun testAddition() {
val result = 2 + 2
assert(result == 4)
println("Test Addition Passed")
}

@Test
fun testSubtraction() {
val result = 5 - 3
assert(result == 2)
println("Test Subtraction Passed")
}
}

در این مثال، متدهای setUpClass و tearDownClass به عنوان متدهایی که قبل و بعد از اجرای همه تستها باید اجرا شوند، با استفاده از Annotationهای BeforeClass@و AfterClass@تعریف شدهاند. این متدها درون یک شیء companion object تعریف شدهاند تا به عنوان متدهای استاتیک در کلاس MyTestClass شناخته شوند.

حالا کمی کاربردی تر مثال بزنیم.فرض کنید میخواید ویومدل خودتون رو تست کنید و براش تست بنویسید.به مثال زیر توجه کنید:

class UserProfileViewModel(private val userRepository: UserRepository) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User>
get() = _user

fun fetchUser(userId: String) {
viewModelScope.launch {
val result = userRepository.getUserById(userId)
if (result.isSuccess) {
_user.value = result.getOrNull()
} else {
// Handle error
}
}
}
}

حالا بیایید یک مثال از تست نویسی برای این کلاس ViewModel بنویسیم، با استفاده از کتابخانهی Mockito و JUnit:

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class UserProfileViewModelTest {

@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()

@Mock
lateinit var userRepository: UserRepository

@Mock
lateinit var userObserver: Observer<User>

private lateinit var userProfileViewModel: UserProfileViewModel

@Before
fun setup() {
userProfileViewModel = UserProfileViewModel(userRepository)
userProfileViewModel.user.observeForever(userObserver)
}

@Test
fun testFetchUserSuccess() {
val userId = "123"
val user = User("123", "John Doe")

// Mocking repository response
Mockito.`when`(userRepository.getUserById(userId)).thenReturn(Result.success(user))

// Call fetchUser method
userProfileViewModel.fetchUser(userId)

// Verify that userObserver d was called and userLiveData has the correct value
Mockito.verify(userObserver).onChanged(user)
}

@Test
fun testFetchUserError() {
val userId = "123"
val errorMessage = "User not found"
// Mocking repository response
Mockito.`when`(userRepository.getUserById(userId)).thenReturn(Result.failure(Throwable(errorMessage)))

// Call fetchUser method
userProfileViewModel.fetchUser(userId)
// Verify that userObserver d was not called (since it's an error scenario)
Mockito.verify(userObserver, Mockito.never()).onChanged(Mockito.any())
}

@After
fun tearDown() {
userProfileViewModel.user.removeObserver(userObserver)
}
}

در این تست نویسی، از Mockito برای ماک کردن UserRepository و ایجاد مقادیر موک استفاده شده است. سپس دو تست برای متد fetchUser نوشته شده است. در تست اول، وقتی که UserRepository موفق باشد، اطمینان حاصل میشود که تغییرات در LiveData کاربر منعکس شود. در تست دوم، وقتی که UserRepository با خطا روبرو میشود، اطمینان حاصل میشود که تغییرات در LiveData کاربر اعمال نشود.

به طور کلی برای توضیح کد بالا داریم:

  1. آمادهسازی (Setup):در مرحله آمادهسازی، ما موکهایی از کلاسهای وابسته را ایجاد میکنیم و ViewModel مورد نظر را میسازیم.
    در این مثال، از کتابخانهی Mockito برای ایجاد موکها استفاده میشود. همچنین یک Observer برای کاربر نیز موک شده و به LiveData کاربر ViewModel اضافه میشود.
  2. تستها:در این بخش، ما تستهای مختلف برای رفتارهای مختلف ViewModel انجام میدهیم.
    در این مثال، دو تست برای متد fetchUser نوشته شده است.
    در تست اول، ما مقدار user را به عنوان نتیجهی موفقیتآمیز از UserRepository موک میکنیم و سپس میبریم ViewModel را تا اطمینان حاصل شود که LiveData کاربر به درستی به روزرسانی شده است.
    در تست دوم، ما مقدار خطایی را برای UserRepository موک میکنیم و سپس میبریم ViewModel را تا اطمینان حاصل شود که LiveData کاربر در صورت بروز خطا به روزرسانی نمیشود.
  3. پایاندهی (Teardown):در این مرحله، ما تمام موکها را مخرب میکنیم و منابع مصرفی را آزاد میکنیم تا هرگونه اثرات جانبی از تستها پاک شوند.
    در این مثال، Observer از LiveData کاربر ViewModel حذف میشود تا منابع مصرفی را آزاد کنیم.

امیدوارم مفید واقع شده باشد😊

تستاندرویدtestjunit
Android Developer
شاید از این پست‌ها خوشتان بیاید