JUnit - 测试已调用方法

时间:2014-12-15 18:36:32

标签: java unit-testing junit

我是单元测试的新手,我正在尝试测试已调用的方法。有问题的方法不会返回任何内容。

public void example (boolean foo) {

    if (foo) {
        processFoo(foo);
    } 
    else if (foo==false) {
        processSomethingElse(foo);
    }
}

我希望能够测试是否正在调用processFoo方法,但我不知道该怎么做。

如果需要进行模拟,那么我必须使用JMockit。谢谢!

4 个答案:

答案 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执行的操作是否为真,而不是其他