我是单元测试的新手,我正在尝试测试已调用的方法。有问题的方法不会返回任何内容。
public void example (boolean foo) {
if (foo) {
processFoo(foo);
}
else if (foo==false) {
processSomethingElse(foo);
}
}
我希望能够测试是否正在调用processFoo
方法,但我不知道该怎么做。
如果需要进行模拟,那么我必须使用JMockit
。谢谢!
答案 0 :(得分:0)
您可以在类中使用计数器变量,并在调用方法时递增它,或使用print语句。如果您无法访问processFoo
方法,那么在另一种方法调用processFoo
时,一个简单的方法是执行此操作,如果这样做的话唯一可以被称为的地方。
例如:
public static int processFooCalls = 0;
// ...
public void example (boolean foo) {
if (foo) {
processFoo(foo);
processFooCalls += 1;
// and/or
System.out.println("processFoo method was called");
}
// ...
}
public static void main (String[] args) {
// main routine here...
System.out.println("'processFoo' was called " + processFooCalls + " times.");
}
如果processFoo
可以在其他地方调用,并且您也需要考虑这种可能性,那么您需要访问processFoo
代码才能执行此操作,例如:
void processFoo( boolean b ) {
// increment number of times processFoo was called here, and/or print, as follows
processFooCalls += 1;
System.out.println("called processFoo method!");
/* some functionality */
}
答案 1 :(得分:0)
查看JMockit文档,您将需要以下工具:
静态模拟:http://jmockit.github.io/tutorial/BehaviorBasedTesting.html#staticPartial
调用计数:http://jmockit.github.io/tutorial/BehaviorBasedTesting.html#constraints
将两者结合在一个测试中(我的语法可能稍微偏离,因为我更习惯于Mockito,但这个概念应该成立):
@Test
public void someTestMethod(@Mocked({"processFoo"}) final ExampleClass exampleclass)
{
new Expectations() {{
exampleclass.processFoo(); times = 1;
}};
exampleclass.example(true);
}
这应该模拟processFoo方法,保留其他所有内容,并检查以确保它只被调用一次。
答案 2 :(得分:0)
对不起我参加派对有点晚了,但我有几点想法。
首先,你提到一个选项是使用JMockit - 它很棒,因为它给你很大的灵活性。如果使用JMockit,那么processFoo()方法的可见性并不重要。让我们看看它可能是什么样子:
public class Subject {
public void example (boolean foo) {
if (foo) {
processFoo(foo);
}
else if (foo==false) {
processSomethingElse(foo);
}
}
private void processFoo(boolean b) {
System.out.println("b = " + b);
}
private void processSomethingElse(boolean bb) {
System.out.println("bb = " + bb);
}
}
因此,对此选项的一个警告是,我将假设processFoo()是您测试主题的一种方法,并且我将使用部分模拟来更改测试主题 - - 不是我真正喜欢做的事情,但这只是一个例子。一般来说,最好只模拟测试主题的依赖关系,而不是测试主题本身的行为 - 你已被告知!请注意,测试主题的processFoo()方法是私有的。我将使用JMockit的部分模拟来替换测试方法,并且新方法的可见性不必与原始方法匹配。
import static org.assertj.core.api.Assertions.assertThat;
import mockit.Mock;
import mockit.MockUp;
import mockit.integration.junit4.JMockit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JMockit.class)
public class SubjectTest {
private Subject testSubject = new Subject();
private boolean processFooCalled = false;
@Before
public void setup() {
new MockUp<Subject>() {
@Mock
public void processFoo(boolean b) {
processFooCalled = true;
};
};
}
@Test
public void should_call_processFoo() {
testSubject.example(true);
assertThat(processFooCalled).isTrue();
}
@Test
public void should_not_call_processFoo() {
testSubject.example(false);
assertThat(processFooCalled).isFalse();
}
}
好的,这是第一个选择。如果您忘记了JMockit,假设您能够继承测试主题并覆盖processFoo()方法,那么它实际上会更容易一些:
public class Subject {
public void example (boolean foo) {
if (foo) {
processFoo(foo);
}
else if (foo==false) {
processSomethingElse(foo);
}
}
protected void processFoo(boolean b) { // NOTE: protected access here!
System.out.println("b = " + b);
}
private void processSomethingElse(boolean bb) {
System.out.println("bb = " + bb);
}
}
因此,在这种情况下,策略只是将测试主题子类化,并替换您希望观察被调用的方法的实现。它可能看起来像这样:
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public class SubjectTest2 {
private Subject testSubject = new TestableSubject();
private boolean processFooCalled = false;
@Test
public void should_call_processFoo() {
testSubject.example(true);
assertThat(processFooCalled).isTrue();
}
@Test
public void should_not_call_processFoo() {
testSubject.example(false);
assertThat(processFooCalled).isFalse();
}
class TestableSubject extends Subject {
@Override
protected void processFoo(boolean b) {
processFooCalled = true;
}
}
}
给它一个旋转。希望它有所帮助!
答案 3 :(得分:0)
不要考虑对此进行任何形式的嘲讽,在这种情况下你所做的就是确保如果你想重构你的代码,你的测试就会失败。在单元测试中有一句口头禅 - &#34;从不测试私人方法&#34;。
您应该做的是测试您调用的方法是否符合您要查看的行为。在这种情况下,当foo
为真时发生的事情是重要的,而不是它调用processFoo
。因此,如果foo
为真,您希望测试processFoo
执行的操作是否为真,而不是其他。