I am trying to set up unit tests for my application. But I am facing an issue with Segment
This is my test class:
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1])
class LoginViewModelTest {
private lateinit var viewModel: LoginViewModel
@Mock
private lateinit var authService: AuthService
@Mock
private lateinit var sharedPreferences: SharedPreferences
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val mMyApplication = mock<Application>()
viewModel = LoginViewModel(mMyApplication, sharedPreferences, authService)
}
@Test
fun test_phone(){
viewModel.isPhone.observeForTesting {
val isPhone = LiveDataTestUtil.getValue(viewModel.isPhone) ?:
return@observeForTesting
Assert.assertFalse(isPhone)
}
}
}
This is failing with this error:
INTERNET permission is required.
java.lang.IllegalArgumentException: INTERNET permission is required.
at com.segment.analytics.Analytics$Builder.<init>(Analytics.java:1068)
at com.app.android.MyApplication.onCreate(MyApplication.kt:42)
MyApplication class is initializing Segment like this:
override fun onCreate() {
val analytics: Analytics = Analytics.Builder( //This is where its failing
applicationContext,
this.getString(R.string.segmentApiKey)
)
.trackApplicationLifecycleEvents()
.build()
// Set the initialized instance as a globally accessible instance.
Analytics.setSingletonInstance(analytics)
}
I found this in StackOverflow
where they are suggesting that we have to init application like this:
protected Context instance() {
ShadowApplication shadowApp = Shadows.shadowOf(this);
shadowApp.grantPermissions("android.permission.INTERNET");
return shadowApp.getApplicationContext();
}
pass instance()
to Segment like this:
Analytics.with(instance()).identify("userId", null, null);
I don't think this is the right way because we are altering the code for the Unit test which is not the correct way IMHO.
I tried it anyway, but it's failing because it cannot resolve shadowApp.getApplicationContext()
I am using shadowApplication by adding this
implementation 'org.robolectric:shadow-framework:4.6'
Please help me figure this out. Thanks in advance.
If using ShadowApplication is the right way, please help me understand what is happening too. My understanding for this code snippet is that it is a sample Application class or something that can be used for Testing. Please cmiiw.
Edit: My AndroidManifest.xml already has internet permission <uses-permission android:name="android.permission.INTERNET"
Well apparently there was something wrong with my setup
I added these
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.13.2'
// Optional -- Robolectric environment
testImplementation 'androidx.test:core:1.4.0'
// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:4.5.0'
// Optional -- mockito-kotlin
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
// Optional -- Mockk framework
testImplementation 'io.mockk:mockk:1.12.3'
testImplementation 'androidx.test.ext:junit-ktx:1.1.3'
testImplementation 'org.robolectric:robolectric:4.6.1'
testImplementation 'org.mockito:mockito-inline:2.13.0'
testImplementation 'android.arch.core:core-testing:1.1.1'
and changed my test class to be like this:
@RunWith(MockitoJUnitRunner::class)
class LoginViewModelTest : TestCase() {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
private lateinit var viewModel: LoginViewModel
@Before
public override fun setUp() {
super.setUp()
val mMyApplication = mock(Application::class.java)
val sharedPreferences = mock(SharedPreferences::class.java)
val authService = mock(AuthService::class.java)
val analyticsFacade = mock(AnalyticsFacadeImpl::class.java)
doNothing().`when`(analyticsFacade).trackEvent(anyString(), any())
viewModel = LoginViewModel(
mMyApplication, sharedPreferences, authService,
analyticsFacade as AnalyticsFacadeImpl)
}
@Test
fun test_phone(){
viewModel.isPhone.observeForTesting {
val isPhone = LiveDataTestUtil.getValue(viewModel.isPhone) ?:
return@observeForTesting
Assert.assertFalse(isPhone)
}
}
}