public class ExampleTest {private Calculator calculator;@Beforepublic void setUp() {calculator = new Calculator();}@Testpublic void testAddition() {// کد تست }}
public class ExampleTest {private DatabaseManager databaseManager;@Afterpublic void tearDown() {databaseManager.closeConnection();}@Testpublic void testDatabaseConnection() {// کد تست}}
حالا BeforeClass@و AfterClass@ چی هستند:مشابه Before و After هستند، اما متدهایی که با این Annotationها مشخص میشوند، قبل و بعد از اجرای همه تستها در یک کلاس اجرا میشوند.
class MyTestClass {companion object {@BeforeClass@JvmStaticfun setUpClass() {// تنظیمات قبل از اجرای همه تستهاprintln("Setting up before all tests...")}@AfterClass@JvmStaticfun tearDownClass() {// پاکسازی بعد از اجرای همه تستهاprintln("Tearing down after all tests...")}}@Testfun testAddition() {val result = 2 + 2assert(result == 4)println("Test Addition Passed")}@Testfun testSubtraction() {val result = 5 - 3assert(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 کاربر اعمال نشود.
به طور کلی برای توضیح کد بالا داریم:
fetchUser نوشته شده است.امیدوارم مفید واقع شده باشد😊