I am writing an App for Android, and I am wanting to start writing tests for the classes I am writing. I am fairly new to writing test cases.
Right now to create a test, I use IntelliJ and use it's wizard to make a new JUnit4 test. The wizard allows me to select methods from my class to test.
But for the object I am testing, I do not want a negative number passed to the constructor.
class MinuteTime(private val minutes : Int) {
init {
if (minutes < 0) {
throw IllegalArgumentException("Cannot be less than 0.")
}
}
...
Where in my Test class is the best place to test these constraints? I know that to test the constraints, I just need to make sure the exception is thrown and caught, but I am unsure if I should make a new method for this, or just wedge it into one of the functions IntelliJ pre-made for me. Here is the generated test class:
class MinuteTimeTest {
#Test
fun getTimeInMinutes() {
}
#Test
fun getHours() {
}
#Test
fun getMinutes() {
}
#Test
fun plus() {
}
}
I'd definetly recommend to wrap this into a separate test method. Its concern is simply testing the validation during initialization:
#Test
fun negativeNumberConstructorTest() {
assertFailsWith(IllegalArgumentException::class){
MinuteTime(-1)
}
}
It’s using kotlintest on top of JUnit
Related
I can't change project code, I can only write tests.
I have a function for testing:
fun funToBeTested() {
ClasWithWorkManager().veryVeryBadFunc(TAG)
// a lot of code to be tested below
...
}
and class with WorkManager:
class ClasWithWorkManager() {
companion object {
#JvmStatic
fun veryVeryBadFunc(tag: String) {
WorkManager.getInstance().cancelAllWorkByTag(tag)
WorkManager.getInstance().pruneWork()
}
}
}
There are no Android class references in the rest of this func.
Can I somehow cover with Unit test all funToBeTested() except of its first line?
Right now I have obvious WorkManager is not initialized properly. problem
I am working on an Android library and I am writing an instrumented test for it using UI Automator and Mockk.
The library has a class called InstallManager which will install stuff on the device. I want the InstallManager to throw an exception so that I can test if an error notification will be shown.
All I do is finding the Update (Install) button and click on it
val updateButtonComponent = device.findObject(By.text(updateButtonText))
updateButtonComponent.click()
How can I mock/manipulate the InstallManager which is being used by the library during the automated test?
What I tried:
I tried mocking the InstallManager before running the automated test, hoping that UI Automator would magically know that it should use this mocked InstallManager. But (as I thought already) it does not work like that...
private fun breakInstallManager() {
installManager = spyk(InstallManager(mockk(relaxed = true), nonExistentFile))
every { installManager.getString(any()) } returns ""
every { installManager.packageName } returns ""
}
For mocking InstallManager class in android tests, call MockKAnnotations.init method. Then in the test method you can specify the return value
#RelaxedMockK
private lateinit var installManager: InstallManager
#Before
fun setUp() {
MockKAnnotations.init(this)
// …
}
#Test
fun installManagerTest(){
every { installManager.getString(any()) } returns ""
every { installManager.packageName } returns ""
// …
}
I want to implement some UI Tests to assure that the code implemented today works for tomorrow but when trying to see if already UI tests implemented in the past works, it throws this error:
Caused by: io.mockk.MockKException: Failed matching mocking signature for left matchers: [any(), any()]
This happens on an every {} return Unit line which there's a object file called WakeUpTimeManager, that calls a .set(param1, param2) function and inside that function there are some inline functions which I think it could be causing the problem but I don't know. I tried searching on the internet but couldn't find a solution.
Here's the test that throws the error:
#Before
fun setup() {
mockkObject(WakeUpTimerManager)
every { WakeUpTimerManager.set(any(), any()) } returns Unit
}
Here's the function that is calling on every line
fun set(context: Context, timer: Timer) {
if (timer.atMillis < System.currentTimeMillis()) {
return
}
if (Preset.findByID(context, timer.presetID) == null) {
return
}
//This is an inline function
withGson {
PreferenceManager.getDefaultSharedPreferences(context).edit {
putString(PREF_WAKE_UP_TIMER, it.toJson(timer))
}
}
//This is an inline function
withAlarmManager(context) {
it.setAlarmClock(
AlarmManager.AlarmClockInfo(timer.atMillis, getPendingIntentForActivity(context)),
getPendingIntentForService(context, timer)
)
}
}
Question: Why does mockk throw this error? What's going on? Is there any solution for this?
try with mockkStatic(WakeUpTimerManager::class). For me mockkObject was not working either, but mockkStatic did
In my case I was using the wrong annotation for mocking dependencies.
I was using #MockBean from org.springframework.boot.test.mock.mockito.MockBean while I should have been using #MockkBean from com.ninjasquad.springmockk.MockkBean.
In my case I used type cast for any(). I wanted to test that a method viewModel.show(Message()) had invoked. But this method is overloaded (has signatures of different types), so I tried to cast parameter any() to Message.
// show is overloaded method
fun show(resourceId: Int) {}
fun show(text: String) {}
fun show(message: Message) {}
// But it threw the exception.
verify { viewModel.show(any() as Message) }
// This won't work because Message() object will be different
verify { viewModel.show(Message()) }
Maybe mocking for message will help, but not in my case.
// val message = mockk<Message>()
// every { Message() } returns message
// verify { viewModel.show(message) }
I had to add mockkStatic, because I used an extension method. For instance, fun ViewExtension.show():
mockkStatic(ViewExtension::class.java.name + "Kt") // Like "com.example...ViewExtensionKt"
Then mock a behaviour:
every { viewModel.show(Message()) } just Runs
verify { viewModel.show(any() as Message) }
Sometimes, especially with Dagger Hilt and global test modules that replace object instances with Mockk mocks, it's not entirely clear whether one works with the mock or the real object. For me it was exactly this - I had a missing dependency, so my real instance was not replaced with the mocked instance, so mockk answered with this really weird error:
io.mockk.MockKException: Failed matching mocking signature for
left matchers: [any()]
at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:99)
at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalVerify(API.kt:119)
at io.mockk.MockKKt.verify(MockK.kt:149)
at io.mockk.MockKKt.verify$default(MockK.kt:140)
I'm running UI testing on Android devices using Appium. We recently migrated to JUnit5 and I'm attempting to utilize the #BeforeAll class to make sure the app is in a good state before we continue to the next class.
Currently, the tooltip in Android studio is indicating that the function is never used. In the log I'm seeing a junitException saying that the method must be static. I haven't implemented #TestInstance yet, I'd like to be able to use beforeAll without it for now. I'm just confused why it isn't working since my #beforeEach and #afterEach are both working. The error and code are below.
org.junit.platform.commons.JUnitException: #BeforeAll method 'public final void com.bypass.automation.BaseTest.healthcheck()' must be static unless the test class is annotated with #TestInstance(Lifecycle.PER_CLASS).
open class BaseTest {
lateinit var driver: AndroidDriver<MobileElement>
private val capabilities = DesiredCapabilities().apply {
setCapability(APPIUM_VERSION, "1.19.1")
setCapability(PLATFORM_NAME, "Android")
setCapability(DEVICE_NAME, "Android")
setCapability("appPackage", "com.ourpackage")
setCapability("appActivity", "com.ourpackage.PassthroughHomeActivity")
setCapability("automationName", "uiautomator2")
setCapability("skipDeviceInitialization", true)
setCapability("noReset", true)
setCapability("full-reset", false)
setCapability("enableMultiWindows", false)
setCapability("unlockType", "pin")
setCapability("unlockKey", "0000")
setCapability("newCommandTimeout", "120")
}
#BeforeAll
fun healthcheck() {
val currentActivity = driver.currentActivity()
println("Current activity is $currentActivity")
if (currentActivity.contains("StationSecurePayActivity")) {
println("Exiting Station Pay")
CreditCardEntryView(driver).clickBackButton()
}
when {
currentActivity.contains("kiosk") -> {
Thread.sleep(2000)
println("Exiting Kiosk")
KioskView(driver).exitKiosk()
println("Logging out")
LogInProviderUtil(driver).logOut()
}
currentActivity != ".LoginActivity" -> {
println("Logging out")
LogInProviderUtil(driver).logOut()
}
currentActivity.contains(".LoginActivity") -> {
println("Session was properly logged out. No action taken.")
}
}
}
#BeforeEach
fun setup() {
driver = AndroidDriver(URL("http://127.0.0.1:4750/wd/hub"), capabilities)
driver.manage()?.timeouts()?.implicitlyWait(30, SECONDS)
if (LogInProviderUtil(driver).isLoggedIn()){
LogInProviderUtil(driver).logOut()
}
}
#AfterEach
fun teardown() {
if (LogInProviderUtil(driver).isLoggedIn()){
LogInProviderUtil(driver).logOut()
driver.quit()
}
else {
driver.quit()
}
}
}
It will work. I believe that any method annotated with #BeforeAll must be static (unless the "per-class" test instance lifecycle is used). So it sounds to me like you should switch to that by adding this annotation to your test class: #TestInstance(Lifecycle.PER_CLASS)
Also, it is usual practice to make your setup and teardown methods public. Also, I recommend use of Selenium-Jupiter framework (https://github.com/bonigarcia/selenium-jupiter/blob/master/README.md#appium) . Good luck.
If you want to have an initialization block you may put it simply into
init{} method. And you don't have to annotate it.
I'm trying to test this code with mockito.
public class Repository {
...
#Override
public Observable<Data> getCurrentData() {
return api.getData()
.map(entityMapper::transform);
}
}
And I would like to test the entityMapper interaction. Here my test scenery:
#Test
#Throws(Exception::class)
fun getData() {
//given
whenever(api.getData).thenReturn(Observable.just(Data()))
//when
debitCardRepo.getCurrentData
//then
verify(api).getData
//TODO verify entityMapper interaction
}
If I try verify(entityMapper).transform(anyOrNull<>()), I will get Wanted but not invoked:
Does anyone knows how to test an mock interaction inside a map/flapmap?
Does anyone knows how to test an mock interaction inside a map/flapmap?
Assuming the rest of your class looks like this:
public class Repository {
private final EntityMapper
public Repository(EntityMapper entityMapper) {
this.entityMapper = entityMapper;
}
#Override
public Observable<Data> getCurrentData() {
return api.getData()
.map(entityMapper::transform);
}
}
Then stubbing a behaviour on a mocked EntityMapper will work if you wait for the Observable to complete:
#Test
#Throws(Exception::class)
fun testGetData() {
//given
val data = Data()
whenever(api.getData).thenReturn(Observable.just(data))
//when
repository.getCurrentData().blockingGet()
//then
verify(entityMapper).transform(any())
}
Note the call to blockingGet() - otherwise it is possible for the test to complete before the mapping has occurred. You should also look at the Observable#test() method to see better options here.
However in this case since the repository does very little apart from delegating to the API and calling the EntityMapper and this seems to be the main interaction you are interested in, why not test EntityMapper separately?
If you write a separate test for EntityMapper then you can use a black-box test (simply call transform on your data and see if the transformation matches your expectations). This kind of test is much more stable and valuable than white-box testing with verify which can sometimes degenerate into tests that are a reverse implementation of system under test.
You didn't subscribe.
debitCardRepo.getCurrentData will just return an Observable but not actually really do anything.
#Test
#Throws(Exception::class)
fun getData() {
//given
whenever(api.getData).thenReturn(Observable.just(Data()))
//when
debitCardRepo.getCurrentData.subscribe()
//then
verify(api).getData
}
regardless, this isn't a great test, as you're testing a side effect happens. some map/transform function is called. Why don't you test the output?
#Test
#Throws(Exception::class)
fun getData() {
//given
val data = Data()
whenever(api.getData).thenReturn(Observable.just(data))
//when
val transformedData = debitCardRepo.getCurrentData.blockingGet()
//then
assertEquals(data, transformedData)
}
This is a more meaningful test. Simple refactors won't break this test unless the change the behavior of the class.