简体   繁体   中英

Mockito doThrow() not throwing exception

There's been similar questions, but none of those can solve my current problem

Say I have a fairly simple class:

public class ClassA {
    private final Object someVariable;
    
    public classA(Object obj) {
        this.someVariable = obj
    }

    public void Object someMethod(Object obj) throws SomeException {
    //does stuff
    }
}

Now, I create an instance of this class in a diff class

public class ClassB {
    private final Object anotherVariable;

    public void Object anotherMethod() throws SomeException {
        try {
            ClassA objectA = new ClassA(anotherVariable)
            objectA.someMethod()
        } catch {
            // does stuff
        }
    }
}

The end goal is to test the catch block by throwing an exceptions as so

@Mock
ClassA myObject = new ClassA(obj)

...

@Test(expected = SomeException.class)
public void myTest()throws Exception {
    doThrow(new SomeException()).when(myObject).someMethod(any());
}

For some reason the exceptions is just never thrown. I've also tried replacing the any() with both valid and invalid objects, and it still doesn't work.

Edit1:

Whilst fishing for a solution, this for some reason passes the test:

@Test(expected = SomeException.class)
public voif Test() throws Exception {     
    doThrow(new someException()).when(myObject).someMethod(any());
    when(myObject.someMethod(any())).thenThrow(new someException());
}

Any explanation as to why this works? Is this bad practice or something?

I believe the reason is that you never call the method:

@Test(expected = SomeException.class)
public void myTest(0 throws Exception {
    // here you stub the method
    doThrow(new SomeException()).when(myObject).someMethod(any());
    // also it should probably be like this:
    // doThrow(new SomeException()).when(myObject).someMethod();
    // because the method in ClassA does not have any params

    // you need it to be called somewhere
    // you can do that explicitly
    myObject.someMethod(/*perhaps some param here*/);

    // or you can call some other method which calls this one
    // on the mock - then you should get an exception as well
}

Also, there is a little issue in ClassB:

public void Object anotherMethod() throws SomeException {
    try {
        // you instantiate obj of type ClassA here
        // which means you cannot mock it if you need
        // to test anotherMethod()
        ClassA objectA = new ClassA(anotherVariable)
        objectA.someMethod()
    } catch {
            // does stuff
    }
}

If you'd like to test ClassB.anotherMethod() you need to get rid of this super tight coupling:

ClassA objectA = new ClassA(anotherVariable)

Consider approach like this:

public class ClassB {
    private final ClassA objectA;

    public ClassB(ClassA obj) {
        // now you can provide any instance of ClassA instead
        // of having it created in try-block later
        // so when you need ClassB in real code, you can create
        // some real instance of ClassA and pass to this conctructor
        // and for test you can pass mock 
        this.objectA = obj;
    }

    public void Object anotherMethod() throws SomeException {
        try {
            objectA.someMethod()
        } catch {
            // does stuff
        }
    }
}

What this gives us:

@Mock
ClassA myObject = new ClassA(obj)

...

@Test(expected = SomeException.class)
public void myTest()throws Exception {
    // stub someMethod on object of ClassA
    doThrow(new SomeException()).when(myObject).someMethod();

    ClassB objB = new ClassB(myObject);
    
    // now you can test it, and inside anotherMethod()
    // there will be a call to someMethod() on a mock
    // so you will get an exception
    objB.anotherMethod();
}

I assume since u are mocking Class A below line

@Mock
ClassA myObject = new ClassA(obj) //u r creating new instance 

do

@Mock
ClassA myObject; //assuming u r using initMock or @InjectMocks

or

ClassA myObject = Mockito.mock(ClassA.class);

then Mock the behavior how u mock a method call

when(myObject.someMethod(any()))
      .thenThrow(new SomeException());

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