Why Log.d() print nothing when running Android Local Unit Test?-ThrowExceptions

Exception or error:

I’m trying to print something when running Android Local Unit Test, but nothing’s happening. What’s the matter? How can I fix it?

I consulted some documents on http://developer.android.com, found that Android Local Unit Test just run on my machine’s JVM, the android.jar file that is used to run unit tests does not contain any actual code, so Log.d() print nothing. If i wanna print log, how can i do?

Here is my code, FeedbackModelTest.java located in src/test/main directory.

package com.upward.reader.mvp.model;

import android.util.Log;

import com.upward.reader.mvp.bean.FeedbackBean;
import com.upward.reader.net.RequestJSONCallback;

import org.junit.Test;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class FeedbackModelTest {

@Test
public void postFeedback() throws Exception {
    final String url = "http://test.guguread.com/interface/app/user/feedback?";
    Map<String, String> params = new HashMap<>();
    params.put("content", "content");
    new FeedbackModel().postFeedback(url, params, new RequestJSONCallback<FeedbackBean>() {

        @Override
        public void onResponse(FeedbackBean result) throws IOException {
            Log.d("TAG", result.toString());
        }

        @Override
        public void onFailure(Exception e) {
            e.printStackTrace();
        }

    });
}

}

How to solve:

You should use standard output, System.out.println("Hello StackOverflow") intead of Log.x(). Then you can see the log info in the run tab.
enter image description here

2017/12/16 Update: If you can’t see the output on the Run tab, go to Android Monitor tab to find the output instead.

###

I suggest you to use interface:

interface PlatformLog {
    fun e(tag: String, msg: String, throwable: Throwable?=null)
    fun i(tag: String, msg: String)
}

create an interface for example:

in unit tests:

class SystemPlatformLog : PlatformLog {
    override fun i(tag: String, msg: String) {
        println("$tag : $msg")
    }

    override fun e(tag: String, msg: String, throwable: Throwable?) {
        println("$tag : $msg")
    }
}

In android

class AndroidPlatformLog : PlatformLog {
                override fun i(tag: String, msg: String) {
                    Log.i(tag, msg)
                }

                override fun e(tag: String, msg: String, throwable: Throwable?) {
                    Log.e(tag, msg, throwable)
                }
            }

Usage:
In android

private val log: PlatformLog = AndroidPlatformLog()

public override fun onCreate(savedInstanceState: Bundle?) {
    log.i(TAG, "onCreate $savedInstanceState")
}

In tests

private val log: PlatformLog = SystemPlatformLog()

@Test
fun `should log in System`() {
    log.i(TAG, "called from tests")
}

OR with dagger2 in two cases:

@Inject lateinit var log: PlatformLog

public override fun onCreate(savedInstanceState: Bundle?) {
    log.i(TAG, "onCreate $savedInstanceState")
}

in tests

class MyTest{

@Inject lateinit var log: PlatformLog

@Before
fun setUp() {
    val component = DaggerTestComponent.builder().testModule(TestModule()).build()
        component.inject(this)
}

@Test
fun `should log in System`() {
    log.i(TAG, "called from tests")
}
@Module
open class TestModule {

    @Provides
    @Singleton
    open fun providePlatformLog(): PlatformLog {
        return SystemPlatformLog()
    }
}
@Singleton
@Component(modules = [TestModule::class])
interface TestComponent {
    fun inject(test: MyTest)
}

###

From Unit Testing Support:

The android.jar file that is used to run unit tests does not contain any actual code – that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito). If that proves problematic, you can add the snippet below to your build.gradle to change this behavior:

  android {
  // ...
  testOptions { 
    unitTests.returnDefaultValues = true
  }
}

###

If you need to involve some form of Android-related code in your tests (which Log.d is), you can use a testing framework such as Robolectric which is designed to act like the Android.jar code that your code references. By configuring your test runner to run in Robolectric, and setting the proper config flag in robolectric’s config annotations, you can enable logging using their logging methods.

Leave a Reply

Your email address will not be published. Required fields are marked *