当使用Robolectric + Roboguice时,日志输出写入到哪里?

52
我正在使用Robolectric测试Android。我通过maven运行我的测试,例如:
mvn -Dtest=LogTest test
如果我有写日志的代码,例如:
Log.d("TAG", "blah");

或者使用Roboguice的Ln

Ln.d("blah");

我在maven的surefire日志(文本文件)中看不到任何输出。

理想情况下,我希望简单的日志语句可以输出到控制台。虽然我可以使用System.out.println("blah")将其输出到控制台,但我更愿意使用支持的日志API。

因此,我的问题是,为什么我根本看不到日志输出,如何将日志消息写入控制台?


它能处理信息/错误吗? - artbristol
这是一个老问题,但我确实想要请求Tyler接受一个答案。当你接受问题的答案时,人们更愿意回答你的问题。 - Christine
@Christine 我同意,但是我已经没有能力检查这里发布的答案是否有效。当时,这里的所有答案都没有帮助到我。我点赞了scompt.com的回答,但后来发现它并没有解决我的问题,正如我在评论中所指出的那样。这么长时间过去了,我应该遵循什么政策/指南呢? - Tyler Collier
Jesus Monzon Legido的解决方案很好,我使用它。此外,这是给出的最简单的解决方案。 - Christine
6个回答

79

我正在运行 robolectric-2.0-alpha-3

对我有效的方法是在我的测试的setUp方法中设置流到stdout

类似于:

@Before
public void setUp() throws Exception {
  ShadowLog.stream = System.out;
  //you other setup here
}

使用此版本的robolectric,我在自定义TestRunner或我的TestLifeycleApplication中尝试进行相同操作(ShadowLog.stream = System.out),但无法成功。

设置系统属性System.setProperty("robolectric.logging","stdout");也没有效果,但在以前的版本中可能有效。


4
好的!我将在一个用@BeforeClass注释的静态方法中调用此代码,以便每个测试文件只运行一次。 - Kai
同样适用于 Robolectric 3.0。 - Ivan Kušt
适用于Robolectric 4.5.1版本。 - thiagolsilva

15

我正在使用 Robolectric 2.3。下面是我的做法:

在我的 @Before 方法中:

ShadowLog.stream = System.out;

在我的测试函数中,我可以使用(ShadowLog. 还有其他选项):

ShadowLog.v("tag", "message");

在我的测试类中,我可以使用以下代码将一些消息记录到日志中:

System.out.println("message");

我已经尝试过了,但是我什么也没看到。输出写在哪里?顺便说一下:我使用的是Robolectric 2.4,但我认为日志记录方式是相同的。 - user2368140
您可以在Logcat中查看结果。请确认您将ShadowLog.stream = System.out; 放入了您的设置中。 - Bamumi
为什么不直接使用 System.out?为什么需要 ShadowLog - IgorGanapolsky

13

使用RobolectricTestRunner时,默认情况下日志输出会消失。您可以通过查看该类的setupLogging()方法来配置日志的存储位置。

简而言之,您需要将robolectric.logging系统属性设置为stdoutstderr或日志应写入的文件路径。我在一个RobolectricTestRunner子类的构造函数中执行此操作,用于所有测试,以便日志始终被写入到标准输出中。


1
成功了!谢谢!链接也很好。现在...你是在哪里读到这个的,还是直接查看源代码?此外,你是否熟悉Roboguice?我想使用他们的“Ln”日志记录,但如果我这样做,它不会被打印到stdout中,尽管它的默认实现似乎是通过android.util.Log,这应该可以工作,因为我可以直接使用Log。你有什么想法? - Tyler Collier
我只是通過深入研究代碼找到了它。我認為這並沒有被文檔化。至於 Ln,請確保您的應用程式是 debuggable,否則 Ln自動禁用調試和冗長記錄 - Edward Dale
抱歉,我有些迟钝。我意识到这并没有真正解决我的问题。你指出的代码是有道理的,但事实上它并不起作用。我本以为它在起作用,但实际上这只是我用来让它工作的剩余代码,来源于:http://groups.google.com/group/robolectric/browse_thread/thread/f1a5df8b3849a4f3?pli=1 - Tyler Collier
1
setupLogging() 仍然存在吗?http://pivotal.github.io/robolectric/javadoc/com/xtremelabs/robolectric/RobolectricTestRunner.html - emmby
是的,它仍然在 RobolectricTestRunner 中,但是软件包已经更改了。 - Edward Dale

5

3
我刚刚用 Robolectric 2.x+ 进行了测试。不再需要使用 Robolectric.bindShadowClass(ShadowLog.class); - Macarse
是的。这个可行。正如@Macarse所说,第二行是不需要的 - robolectric 2.2。 - Julian A.
我遇到了一个错误 **无法解析方法'bindShadowClass'**。 - IgorGanapolsky

2

使用Maven运行测试只需要像这样:

                 <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.17</version>
                    <configuration>
                        <systemPropertyVariables>
                          <robolectric.logging>stdout</robolectric.logging>
                        </systemPropertyVariables>
                    </configuration>
                 </plugin>

当在本地运行测试,例如在Intellij中时,您只需要一个环境变量:

只需进入(对于Intellij)Run/Debug Configurations --> Defaults --> Junit --> VM options,并添加即可。

-Drobolectric.logging=stdout

0
对我来说(或者说根本就是)最好的解决方案是,在测试期间初始化一个替换注入实现的RoboGuice的Ln.Print类,以进行System.out打印而不是Android的Log打印,因为我实际上正在使用Robolectric,避免了首先依赖于Android子系统来运行我的测试。
Ln.java
public class Ln  {
...

/**
 * print is initially set to Print(), then replaced by guice during
 * static injection pass.  This allows overriding where the log message is delivered to.
 */
@Inject protected static Print print = new Print();

基本上就是:

public class TestModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Ln.Print.class).to(TestLogPrint.class);
    }

}

并且:

public class TestLogPrint extends Print {

    public int println(int priority, String msg ) {

        System.out.println(
            String.format(
                "%s%s", 
                getScope(4), 
                msg
            )
        );

        return 0;
    }

    protected static String getScope(int skipDepth) {
        final StackTraceElement trace = Thread.currentThread().getStackTrace()[skipDepth];
        return String.format("%s | %s.%s | ", new Date(), trace.getFileName().replace(".java", ""), trace.getMethodName());
    }
}

当然,这是在假设使用标准的Robolectric init来将模块与RoboGuice连接的情况下。
@Before
public void setUp() throws Exception {

    Module roboGuiceModule = RoboGuice.newDefaultRoboModule(Robolectric.application);
    Module productionModule = Modules.override(roboGuiceModule).with(new CustomRoboModule());
    Module testModule = Modules.override(productionModule).with(new TestModule());

    RoboGuice.setBaseApplicationInjector(Robolectric.application, RoboGuice.DEFAULT_STAGE, testModule);
    RoboGuice.injectMembers(Robolectric.application, this);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接