I got above error when i use mockhttpserver to test http request, the following code is how i create service.
fun <T> getService(clazz: Class<T>): T {
val client = OkHttpClient.Builder().addInterceptor(HeaderInterceptor()).addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE })
.build()
return Retrofit.Builder()
.baseUrl(mockWebServer.url(""))
.client(client)
.addConverterFactory(GsonConverterFactory.create(GSON))
.build()
.create(clazz)
}
This is my Test code.
@UninstallModules(HomePageDataModule::class)
@HiltAndroidTest
class TestHomePageViewModel {
private lateinit var viewModel: HomePageViewModel
@get:Rule
var hiltRule = HiltAndroidRule(this)
@Inject
lateinit var cpd: CompositionDao
@Inject
lateinit var csd: CompositionsDao
@Inject
lateinit var hpds: HomePageDataSource
@Inject
lateinit var ss :HomePageService
@Before
fun init() {
hiltRule.inject()
viewModel = HomePageViewModel(HomeCompositionsRepository(cpd, csd, hpds, Util.GSON))
}
@Test
fun testObserveHomeData() {
val data = Util.getFileString("mainpage.json")
val rr = GSON.fromJson(data,Array<HomePreviewView>::class.java)
println(rr)
enqueueResponse("mainpage.json")
runBlocking {
val result = ss.getHomeData()
Assert.assertNotEquals(rr.size,result.body()!!.size)
}
}
Everything works smoothly on my app except running my unit test code. There is a similar problem , but my issue has a little difference compare to that one. Plenty of ways from that similar question i have tried, but not work.
PS: If the test code run on Junit4Test but not AndroidJunit4Test, it works properly. But now i need to exectue a integrate test. So this part of code need to be executed on AndroidJunit4Test
Cleartext is any transmitted or stored information that is not encrypted or meant to be encrypted. When an app communicates with the server using a cleartext network traffic, such as HTTP, it could raise the risk of eavesdropping and tampering of content.
Open the AndroidManifest. xml file and under the <application> tag, add the specific line that android:usesCleartextTraffic=”true” enables the HTTP connection, which is disabled by default after the release of Marshmallow. Now run your application.
Resolution. If your application must support loading plain http:// URLs, you can opt into enabling cleartext traffic by using an AndroidManifest. xml file that includes an android:usesCleartextTraffic="true" application attribute.
Solution 1)
Add the following attribute to the <application
tag in AndroidManifest.xml:
android:usesCleartextTraffic="true"
Solution 2)
Add android:networkSecurityConfig="@xml/network_security_config"
to the <application
tag in app/src/main/AndroidManifest.xml
:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
With a corresponding network_security_config.xml
in app/src/main/res/xml/
:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
In my case, I added this to the android manifest file:
android:usesCleartextTraffic="true"
Problem finally solved according to @Yuri Schimke prompt.
First step: mockwebserver use https
val mockWebServer = MockWebServer().apply {
val localhost: String = InetAddress.getByName("localhost").canonicalHostName
val localhostCertificate: HeldCertificate = HeldCertificate.Builder().addSubjectAlternativeName(localhost)
.build()
val serverCertificates = HandshakeCertificates.Builder()
.heldCertificate(localhostCertificate)
.build()
useHttps(serverCertificates.sslSocketFactory(), false)
}
Second step: use unsafe okhttp client
private fun getUnsafeOkHttpClient(): OkHttpClient.Builder? {
return try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts: Array<TrustManager> = arrayOf<TrustManager>(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
)
// Install the all-trusting trust manager
val sslContext: SSLContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory: SSLSocketFactory = sslContext.getSocketFactory()
val builder: OkHttpClient.Builder = OkHttpClient.Builder()
builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier(HostnameVerifier { hostname, session -> true })
builder
} catch (e: Exception) {
throw RuntimeException(e)
}
}
After finished this, you can create your own service as following code.
fun <T> getService(clazz: Class<T>): T {
val client =getUnsafeOkHttpClient()!!.addInterceptor(HeaderInterceptor())
.addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE })
.build()
return Retrofit.Builder()
.baseUrl(mockWebServer.url(""))
.client(client)
.addConverterFactory(GsonConverterFactory.create(GSON))
.build()
.create(clazz)
}
Hope this is helpful if you have okhttp unit tests on AndroidJunit4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With