我还有最后一节课,大概是这样的:

public final class RainOnTrees{

   public void startRain(){

        // some code here
   }
}

我在其他一些类中使用这个类,像这样:

public class Seasons{

   RainOnTrees rain = new RainOnTrees();

   public void findSeasonAndRain(){

        rain.startRain();

    }
}

在我的JUnit测试类Seasons.java中,我想模拟RainOnTrees类。我怎么能用Mockito做到这一点?


当前回答

我克服了这条信息:

org.mockito.exceptions.base.MockitoException: 不能模拟/间谍类org.slf4j.impl.Log4jLoggerAdapter Mockito不能模仿/侦察,因为: 最终类或匿名类

从这个:log = spy(log);

用这个代替:

log = mock(Logger.class);

这样就有用了。

我猜“默认”记录器适配器是final类的一个实例,所以我不能“侦察”它,但我可以模拟整个事情。去图…

这可能意味着你可以用其他一些“非最终”实例来代替它,如果你有的话。或者简化版本等等。就其价值而言……

其他回答

请看JMockit。它有大量的文档和示例。这里你有一个解决你的问题的例子(为了简化,我添加了构造函数到Seasons注入模拟RainOnTrees实例):

package jmockitexample;

import mockit.Mocked;
import mockit.Verifications;
import mockit.integration.junit4.JMockit;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class SeasonsTest {

    @Test
    public void shouldStartRain(@Mocked final RainOnTrees rain) {
        Seasons seasons = new Seasons(rain);

        seasons.findSeasonAndRain();

        new Verifications() {{
            rain.startRain();
        }};
    }

    public final class RainOnTrees {
        public void startRain() {
            // some code here
        }

    }

    public class Seasons {

        private final RainOnTrees rain;

        public Seasons(RainOnTrees rain) {
            this.rain = rain;
        }

        public void findSeasonAndRain() {
            rain.startRain();
        }

    }
}

对我们来说,这是因为我们从koin-test中排除了mockito-inline。一个gradle模块实际上需要这个,并且由于某些原因,它只在发布版本中失败了(IDE中的调试版本可以工作):-P

只有在Mockito v2中才可以模拟final/static类/方法。

添加到你的gradle文件:

testImplementation 'org.mockito:mockito-inline:2.13.0'

这是不可能与Mockito v1,从Mockito常见问题:

Mockito的局限性是什么 需要java1.5 + 不能模拟最终类 ...

由RC和Luigi R. Viggiano共同提供的解决方案可能是最好的主意。

尽管Mockito在设计上不能模拟final类,但是委托方法是可能的。这有它的优点:

如果API一开始就打算将类改为非final类(final类有其好处),那么不必强制将类改为非final类。 您正在测试API周围装饰的可能性。

在您的测试用例中,您故意将调用转发到被测试的系统。因此,通过设计,你的装饰什么都不做。

因此,测试还可以证明用户只能修饰API,而不能扩展API。

从更主观的角度来看: 我更喜欢将框架保持在最低限度,这就是为什么JUnit和Mockito通常对我来说就足够了。事实上,以这种方式限制有时也会迫使我进行重构。

为那些在Android + Kotlin上面临相同问题(Mockito + Final Class)的人节省时间。在Kotlin中,默认情况下类是final的。我在谷歌的一个Android样本中找到了一个解决方案。解决方案从这里选择:https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample

创建以下注释:

/**
 * This annotation allows us to open some classes for mocking purposes while they are final in
 * release builds.
 */
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass

/**
 * Annotate a class with [OpenForTesting] if you want it to be extendable in debug builds.
 */
@OpenClass
@Target(AnnotationTarget.CLASS)
annotation class OpenForTesting

修改gradle文件。举个例子:https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle

apply plugin: 'kotlin-allopen'

allOpen {
    // allows mocking for classes w/o directly opening them for release builds
    annotation 'com.android.example.github.testing.OpenClass'
}

现在你可以注释任何类,使其开放测试:

@OpenForTesting
class RepoRepository