简体   繁体   中英

JUnit/Mockito test failing for bizarre reason

I have a very simple method that I am trying to unit test:

public class MyAntTask extends org.apache.tools.ant.Task {
    public void execute() {
        fire();
    }

    public void fire() {
        // Do stuff
    }
}

I just want to write a unit test that confirms that calling execute() always invokes fire() , so I wrote this:

@Test
public void executeCallsFire() {
    //GIVEN
    MyAntTask myTask = Mockito.mock(MyAntTask.class);

    // Configure the mock to throw an exception if the fire() method
    // is called.
    Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire();

    // WHEN
    try {
        // Execute the execute() method.
        myTask.execute();

        // We should never get here; HOWEVER this is the fail() that's
        // being executed by JUnit and causing the test to fail.
        Assert.fail();
    }
    catch(Exception exc) {
        // THEN
        // The fire() method should have been called.
        if(!exc.getMessage().equals("fired"))
            Assert.fail();
    }
}

I guess (and I'm by no means an expert) Mockito normally can't mock methods that return void , but this is a workaround. You basically say "wrap my object with a Mock that will always return a specific RuntimeException whenever a particular method is about to get executed". So, instead of fire() actually executing, Mockito just sees that its about to execute and throws an exception instead. Execution verified? Check.

Instead of passing, it fails at the first Assert.fail() just below the call to myTask.execute() .

For the life of me, I can't figure out why. Here's the first 10-or-so lines of the enormous stack trace JUnit is giving me for the fail:

java.lang.AssertionError
    at org.junit.Assert.fail(Assert.java:92)
    at org.junit.Assert.fail(Assert.java:100)
    at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)

Any thoughts here, ye Mockito Gurus of StackOverflow ? Thanks in advance!

Because myTask is a mock, the real object isn't called at all. To call a real object, use a spy.

You can test that a method is called using verify so there's no need for the exceptions.

public void executeCallsFire() {
    MyAntTask myTask = Mockito.spy(new MyAntTask());

    myTask.execute();

    Mockito.verify(myTask).fire();
}

Wanting to mock the object that you're testing doesn't seem right though. It's usually better to design the test so that you're verifying calls to a separate object instead.

I see here more design issue:

  1. why do you need one line method and both of them are public?
  2. the mocks are for simulating dependencies and not for the class under test
  3. if you'll make fire (quite unclear name) as private. You shouldn't test private behavior of your class

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM