在Android Studio JUnit测试中记录日志消息

3 浏览
0 Comments

在Android Studio JUnit测试中记录日志消息

在Android Studio中运行JUnit(method)测试时,有没有办法打印出Logcat(Log.i,Log.d)消息?

我可以看到System.out.print的消息,但没有Logcat的输出。

在runconfiguration(Android Studio的GUI窗口中)中,Android测试下有logcat选项,但是JUnit测试没有。

这可能吗?谢谢任何提示!

0
0 Comments

问题的出现原因是在Android Studio的JUnit测试中,无法直接使用android.util.Log类进行日志记录,因为android.util.Log的实现在本地JVM上运行的单元测试中不可用。这是因为"用于运行单元测试的android.jar文件不包含任何实际的代码(这些API仅由设备上的Android系统映像提供)"。所以如果想要在JUnit测试中使用android.util.Log,需要在本地模拟它,并利用System.out.print打印到控制台。

解决方法是使用PowerMockito来进行模拟。首先,在项目中添加PowerMockito的依赖项。如果使用Gradle,可以添加以下依赖项:

testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock:1.6.5'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'

然后,可以使用Steve在这里的答案来返回传递给模拟对象的参数。具体实现代码如下:

import android.util.Log;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Log.class})
public class SomeUnitTest {
    public void testSomething() {
        System.out.println("Running test"); 
        PowerMockito.mockStatic(Log.class);
        // Log warnings to the console        
        when(Log.w(anyString(), anyString())).thenAnswer(new Answer<Void>()      {
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                if (args.length > 1) { //cause I'm paranoid
                    System.out.println("Tag:" + args[0] + " Msg: " + args[1]);
                }
                return null;
            }
        });
        Log.w("My Tag", "This is a warning");
    }
}

希望这对某些人有所帮助!同时,建议尽量避免使用PowerMock,而是使用标准的面向对象编程实践来实现所需的行为。

0
0 Comments

问题:在Android Studio的JUnit测试中,日志消息无法在控制台中输出。

原因:在JUnit测试中,Android Studio默认不会输出日志消息。因此,需要创建一个自定义的Log类来替代Android中的Log类,以便在JUnit测试中输出日志消息。

解决方法:按照以下步骤创建自定义的Log类,并将其放置在正确的位置。

1. 创建一个名为"Log.java"的文件。

2. 将该文件放置在"test/java/android/util/"目录下。

3. 在"Log.java"文件中,添加以下代码:

package android.util;
public class Log {
    public static int d(String tag, String msg) {
        System.out.println("DEBUG: " + tag + ": " + msg);
        return 0;
    }
    
    public static int i(String tag, String msg) {
        System.out.println("INFO: " + tag + ": " + msg);
        return 0;
    }
    
    public static int w(String tag, String msg) {
        System.out.println("WARN: " + tag + ": " + msg);
        return 0;
    }
    
    public static int e(String tag, String msg) {
        System.out.println("ERROR: " + tag + ": " + msg);
        return 0;
    }
}

4. 在JUnit测试中,使用自定义的Log类来输出日志消息。

通过以上步骤,可以在Android Studio的JUnit测试中输出日志消息,并在控制台中查看输出结果。

0
0 Comments

在Android Studio的JUnit测试中,无法看到Logcat的输出,因为Logcat是Android的特性,JUnit测试只能使用标准的Java,因此Android的特性无法正常工作。

在单元测试中,你可以将“测试替身”注入到被测试的组件中。但是,Log.x调用是静态的,因此无法重写它们(除非使用PowerMock等工具,但应尽量避免使用)。

因此,第一步是引入一个非静态类,作为Log.x调用的代理:

/**
 * 这个类是一个非静态的日志记录器
 */
public class Logger {
    public void e(String tag, String message) {
        Log.e(tag, message);
    }
    public void w(String tag, String message) {
        Log.w(tag, message);
    }
    public void v(String tag, String message) {
        Log.v(tag, message);
    }
    public void d(String tag, String message) {
        Log.d(tag, message);
    }
}

在现有的每个Log.x调用的地方使用这个类。

第二步是编写一个Logger的测试替身实现,将其重定向到标准输出:

public class UnitTestLogger extends Logger{
    public void e(String tag, String message) {
        System.out.println("E " + tag + ": " + message);
    }
    // 其他方法类似
}

最后一步是在单元测试中将UnitTestLogger注入到Logger的位置:

(MockitoJUnitRunner.class)
public class SomeClassTest {
    private Logger mLogger = new UnitTestLogger();
    private SomeClass SUT;
    public void setup() throws Exception {
        SUT = new SomeClass(/* 其他依赖项 */ mLogger);
    }
}

如果你想严格遵守面向对象编程的概念,可以为Logger和UnitTestLogger提取一个公共接口。

话虽如此,我从未遇到过需要在单元测试中调查Log.x调用的情况。我怀疑你也不需要这样做。你可以在调试模式下运行单元测试,并逐行调试代码,这比尝试调查logcat输出要快得多...

一般建议:

如果你正在测试的代码中包含Log.x静态调用,并且你的单元测试没有崩溃-那就有问题了。

我猜测要么所有的测试都是用Robolectric运行的,要么你在build.gradle中有这样的语句:unitTests.returnDefaultValues = true。

如果你用Robolectric运行所有的测试,那么这只是效率低下,但如果所有的Android调用都返回默认值,那么你的测试套件就不可靠。我建议你在继续之前解决这个问题,因为它迟早会给你带来麻烦。

你可以通过将Logger实例命名为Log而不是mLogger来避免完全改变Log调用的需要。

我会将UnitTestLogger重命名为ConsoleLogger以增加清晰度。

我同意,ConsoleLogger会是一个更具描述性的名称。

0