2016-08-21 129 views
1

我是用java编写测试的新手,似乎无法测试某个类的方法是否被调用。Mockito - 测试一个类的方法是否被调用

我正在发送指标给datadog,并且想要在代码中测试是否调用了另一个类的函数。

它说我需要先嘲笑,但我无法让它工作。

MetricRecorder.java

import com.timgroup.statsd.StatsDClient; 
import com.timgroup.statsd.NonBlockingStatsDClient; 
import com.google.common.base.Preconditions; 

public class MetricRecorder { 
    private final String namespace; 
    private final static StatsDClient metrics = new NonBlockingStatsDClient(
     "my.prefix",       
     "localhost",       
     8125,         
     new String[] {"tag:value"} 
    ); 

    public MetricRecorder(String namespace) { 
     Preconditions.checkNotNull(namespace); 
     this.namespace = namespace; 
    } 

    public void inc(String metricName) { 
     this.inc(metricName, 1); 
    } 

    public void inc(final String metricName, final long value) { 
     Preconditions.checkNotNull(metricName); 
     try { 
      metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value); 
     } catch (Exception e) { 
      logger.warn("Unable to record metric {} due to :", metricName, e); 
     } 
    } 
    ... 
} 

MetricRecorderTest.java

public class MetricsRecorderTest { 

    @Test 
    public void metricsRecorderTest() { 
     MetricRecorder recorder = new MetricRecorder("dev"); 
     recorder.inc("foo", 1); 
     verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1); 
    } 
} 

当我运行测试,我得到这个=> org.mockito.exceptions.misusing.NotAMockException: 参数传递给验证( )是NonBlockingStatsDClient类型,不是模拟的!

任何想法,如果我应该测试recordHistogramValue是否被调用,如果是的话,什么参数?

回答

1

由于它看起来像StatsDClient是某种类型的接口,它会使您的测试工作更容易,只需将此依赖项注入到对象中即可。即使你没有使用像Spring或Guice这样的IoC容器,你仍然可以通过简单地通过构造函数传入它的一个实例来控制它。

public MetricRecorder(String namespace, StatsDClient client) { 
    Preconditions.checkNotNull(namespace); 
    Preconditions.checkNotNull(client); 
    this.namespace = namespace; 
    this.client = client; 
} 

这将使您的测试更简单,因为您真正需要做的就是模拟在测试过程中传入的对象。

现在,它失败的原因是因为你将new连接到实例,并且Mockito(在当前配置中)没有装备来模拟新实例。坦率地说,这个设置将使测试更容易进行,而且您应该只需要在一个区域配置您的客户端。

@RunWith(MockitoJUnitRunner.class) 
public class MetricsRecorderTest { 

    @Test 
    public void metricsRecorderTest() { 
     StatsDClient dClientMock = Mockito.mock(StatsDClient.class); 
     MetricRecorder recorder = new MetricRecorder("dev", dClientMock); 
     recorder.inc("foo", 1); 
     verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1); 
    } 
} 
+0

你是否建议我除了我已经有的构造函数外还使用这个构造函数模式?我认为这将工作在技术上....只有其他变化,我将不得不做的是公共最终静态StatsDClient指标私人静态StatsDClient指标...它必须公开测试recorder.metrics,它不能是最终的无论是。 –

0

你在这里弄错了。您不使用嘲讽框架来测试您的“正在测试的课程”。

您使用嘲讽框架创建嘲笑对象;然后在测试用例中将其传递给“正在测试的课程”。然后你的“测试代码”在模拟对象上调用方法;并通过控制返回的值(或通过验证你的模拟会发生什么);这就是你如何编写测试用例。

因此,您的MetricRecorder测试用例不会模拟MetricRecorder;它应该模拟StatsDClient类;正如Makoto所建议的那样;使用依赖项注入将该类的对象放入MetricRecorder中。另外:基本上写“可测试”代码是需要实践的东西。如果您认真对待这项业务,我衷心推荐您观看这些videos。他们全部;真的(值得每秒!)。

相关问题