Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/195.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在android studio junit测试中记录消息_Android_Android Studio_Junit_Logcat - Fatal编程技术网

在android studio junit测试中记录消息

在android studio junit测试中记录消息,android,android-studio,junit,logcat,Android,Android Studio,Junit,Logcat,在Android Studio中运行JUnit(方法)测试时,有没有打印Logcat(Log.i,Log.d)消息的方法 我可以看到System.out.print消息,但没有logcat打印输出 在runconfiguration(androidstudio的GUI窗口)中,有用于Android测试的logcat选项,但不用于JUnit测试 这有可能吗?谢谢你的提示 我一直在寻找同样的东西,却没有找到一个直接的答案。我知道这个问题已经有一年多的历史了,但仍然有一个好的答案供将来参考 在本地JV

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

我可以看到System.out.print消息,但没有logcat打印输出

在runconfiguration(androidstudio的GUI窗口)中,有用于Android测试的logcat选项,但不用于JUnit测试


这有可能吗?谢谢你的提示

我一直在寻找同样的东西,却没有找到一个直接的答案。我知道这个问题已经有一年多的历史了,但仍然有一个好的答案供将来参考

在本地JVM上运行单元测试时,android.util.Log类直接登录到Logcat,android.util.Log的实现不可用。在单元测试中尝试使用Log类时,您将收到一个错误,因为“用于运行单元测试的android.jar文件不包含任何实际代码(这些API仅由设备上的android系统映像提供)。”

因此,如果您真的想使用android.util.Log,您需要在本地模拟它,并利用System.out.print打印到控制台。首先,将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的答案来了解如何使用Mockito返回传递到模拟对象中的参数

结果是:

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 {

    @Test
    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>()      {
            @Override
            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");
    }
}
导入android.util.Log;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.mockito.invocation.invocationMock;
导入org.mockito.stubing.Answer;
导入org.powermock.api.mockito.PowerMockito;
导入org.powermock.core.classloader.annotations.PrepareForTest;
导入org.powermock.modules.junit4.PowerMockRunner;
导入静态org.mockito.Matchers.anyString;
导入静态org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Log.class})
公共类单元测试{
@试验
公共空间{
System.out.println(“运行测试”);
mockStatic(Log.class);
//将警告记录到控制台
当(Log.w(anyString(),anyString())。然后回答(new Answer()){
@凌驾
公共Void应答(invocationmock调用)抛出可丢弃的{
对象[]args=invocation.getArguments();
如果(args.length>1){//因为我有妄想症
System.out.println(“标记:+args[0]+”消息:+args[1]);
}
返回null;
}
});
w(“我的标签”,“这是一个警告”);
}
}

希望这对别人有帮助

在单元测试中不会看到Logcat输出,因为Logcat是Android功能-JUnit测试只能使用标准Java,因此Android功能无法工作

在单元测试中,您可以做的是将“测试加倍”注入到被测试的组件中。但是
Log.x
调用是静态的,因此您无法覆盖它们(如果不解析为例如PowerMock,您应该不惜一切代价避免)

因此,第一步是引入一个非静态类,它将充当
Log.x
调用的代理:

/**
 * This class is a non-static logger
 */
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{

    @Override
    public void e(String tag, String message) {
        System.out.println("E " + tag + ": " + message);
    }

    // similar for other methods
}
最后一步是在单元测试中插入
UnitTestLogger
而不是
Logger

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

    private Logger mLogger = new UnitTestLogger();

    private SomeClass SUT;

    @Before
    public void setup() throws Exception {
        SUT = new SomeClass(/* other dependencies here */ mLogger);
    }

}
如果您想严格遵守OOP概念,可以为
Logger
UnitTestLogger
提取公共接口

也就是说,我从来没有遇到过在单元测试中调查
Log.x
调用的需要。我猜你也不需要它。您可以在调试模式下运行单元测试,并在调试器中逐行检查代码,这比尝试调查logcat输出要快得多

一般建议:

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

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


如果您使用
Robolectric
运行所有测试,那么它就是无效的,但是如果所有Android调用都返回默认值,那么您的测试套件就不可靠。我建议您在继续之前解决此问题,因为它将以某种方式在未来对您造成伤害。

我将采用@Vasily的方法,但需要做一点小小的更改。我们实际上可以使用configured with在测试输出屏幕上记录消息,而不是使用
System.out.println
进行日志记录

这可以通过以下列出的简单步骤实现

第1步: 定义自己的日志级别

  public enum LogLevel {
    VERBOSE,
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    SILENT
}
第二步: 定义记录器抽象

public abstract class Logger {

    ....

    public abstract void debug(String tag, String message);

    public abstract void error(String tag, String message);
   ....

}
第三步: 基于java.util.Logging的记录器实现

public class JavaLogger extends Logger {

    private java.util.logging.Logger mLogger;

    public JavaLogger(LogLevel logLevel, String name) {
        mLogger = java.util.logging.Logger.getLogger(name);
        ConsoleHandler handler = new ConsoleHandler();
        Level level = mapLogLevel(logLevel);
        handler.setLevel(level);
        mLogger.addHandler(handler);
        mLogger.setLevel(level);
    }

    @Override
    public void debug(String tag, String message) {
        if (isLoggable(LogLevel.DEBUG)) {
            mLogger.finer(message);
        }
    }

    @Override
    public void error(String tag, String message) {
        if (isLoggable(LogLevel.ERROR)) {
            mLogger.severe(message);
        }
    }

    ....

    private Level mapLogLevel(LogLevel logLevel) {
        Level level = Level.OFF;
        switch (logLevel) {
            case INFO:
                level = Level.INFO;
                break;

            case WARNING:
                level = Level.WARNING;
                break;

            case ERROR:
                level = Level.SEVERE;
                break;

            case VERBOSE:
                level = Level.FINEST;
                break;

            case DEBUG:
                level = Level.FINER;
                break;

            case SILENT:
                level = Level.OFF;
                break;

            default:
                // no impl
        }

        return level;
    }
}
public class AndroidLogger extends Logger {

public AndroidLogger(LogLevel logLevel) {
    super(logLevel);
}

 ....

@Override
public void debug(String tag, String message) {
    if (isLoggable(LogLevel.DEBUG)) {
        Log.d(tag, message, null);
    }
}

@Override
public void error(String tag, String message) {
    if (isLoggable(LogLevel.ERROR)) {
        Log.e(tag, message, tr);
    }
}

....
第4步: 基于android.util.Log的记录器实现

public class JavaLogger extends Logger {

    private java.util.logging.Logger mLogger;

    public JavaLogger(LogLevel logLevel, String name) {
        mLogger = java.util.logging.Logger.getLogger(name);
        ConsoleHandler handler = new ConsoleHandler();
        Level level = mapLogLevel(logLevel);
        handler.setLevel(level);
        mLogger.addHandler(handler);
        mLogger.setLevel(level);
    }

    @Override
    public void debug(String tag, String message) {
        if (isLoggable(LogLevel.DEBUG)) {
            mLogger.finer(message);
        }
    }

    @Override
    public void error(String tag, String message) {
        if (isLoggable(LogLevel.ERROR)) {
            mLogger.severe(message);
        }
    }

    ....

    private Level mapLogLevel(LogLevel logLevel) {
        Level level = Level.OFF;
        switch (logLevel) {
            case INFO:
                level = Level.INFO;
                break;

            case WARNING:
                level = Level.WARNING;
                break;

            case ERROR:
                level = Level.SEVERE;
                break;

            case VERBOSE:
                level = Level.FINEST;
                break;

            case DEBUG:
                level = Level.FINER;
                break;

            case SILENT:
                level = Level.OFF;
                break;

            default:
                // no impl
        }

        return level;
    }
}
public class AndroidLogger extends Logger {

public AndroidLogger(LogLevel logLevel) {
    super(logLevel);
}

 ....

@Override
public void debug(String tag, String message) {
    if (isLoggable(LogLevel.DEBUG)) {
        Log.d(tag, message, null);
    }
}

@Override
public void error(String tag, String message) {
    if (isLoggable(LogLevel.ERROR)) {
        Log.e(tag, message, tr);
    }
}

....
}

第五步: 为over Logger实现创建一个简单的包装器类

   public class AppLogger { 

    private static Logger sLogger;

   public static void init(Logger logger) {
        sLogger = logger;
    }

   public static void debug(final String tag, String message) {
        sLogger.debug(tag, message);
    }

    public static void error(final String tag, String message) {
        sLogger.error(tag, message, null);
    }

    public static void error(final String tag, String message, Throwable t) {
        sLogger.error(tag, message, t);
    }

    ... 
}
步骤6:初始化

Android

创建方法的应用

AppLogger.init(new AndroidLogger(LogLevel.DEBUG));
Junit

AppLogger可以在@BeforeClass或@Before中初始化

AppLogger.init(new JavaLogger(LogLevel.DEBUG, "test-logger"));

现在您可以在Android Studio的测试运行窗口中观察日志消息了

如果您仍然选择使用黑客解决方案(使用PowerMockito),我实现了以下类来模拟所有Android日志函数

导入android.util.Log;
导入org.junit.BeforeClass;
导入org.junit.runner.RunWith;
导入org.mockito.invocation.invocationMock;
导入org.mockito.stubing.Answer;
导入org.powermock.api.mockito.PowerMockito;
导入org.powermock.core.classloader.annotations.PrepareForTest;
接口信息处理器