Mockito doThrow() не генерирует исключение

#java #mockito

#java #mockito

Вопрос:

Были похожие вопросы, но ни один из них не может решить мою текущую проблему

Допустим, у меня есть довольно простой класс:

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

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

Теперь я создаю экземпляр этого класса в классе diff

 public class ClassB {
    private final Object anotherVariable;

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

Конечная цель — протестировать блок catch, создав исключения таким образом

 @Mock
ClassA myObject = new ClassA(obj)

...

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

  

По какой-то причине исключения просто никогда не выбрасываются. Я также пытался any() заменить как на допустимые, так и на недопустимые объекты, и это все равно не работает.

Правка1:

Во время поиска решения это по какой-то причине проходит тест:

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

Любое объяснение того, почему это работает? Это плохая практика или что-то в этом роде?

Комментарии:

1. Попробуйте это doThrow(SomeException.class)

Ответ №1:

Я считаю, что причина в том, что вы никогда не вызываете метод:

 @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
}
  

Кроме того, в 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
    }
}
  

Если вы хотите протестировать ClassB.anotherMethod() , вам нужно избавиться от этой сверхтяжелой связи:

 ClassA objectA = new ClassA(anotherVariable)
  

Рассмотрите такой подход:

 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
        }
    }
}
  

Что это нам дает:

 @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();
}
  

Комментарии:

1. Это сработало! Моя следующая проблема / вопросы: конечная цель — в основном протестировать блок catch в ClassB, где вызывается someMethod, с помощью doThrow() Я попытался вызвать anotherMethod, который, в свою очередь, вызывает someMethod, но безуспешно

2. @ElizabethSallow Я обновил свой ответ более подробной информацией о том, как вы можете протестировать свой ClassB. Надеюсь, они имеют какой-то смысл 🙂

3. О, теперь это имеет больше смысла, спасибо! Поддержано и принято в качестве ответа.

Ответ №2:

Я предполагаю, что, поскольку вы издеваетесь над классом A ниже строки

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

сделать

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

или

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

затем имитируйте поведение, как вы имитируете вызов метода

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

Комментарии:

1. К сожалению, не сработало, хотя могу ли я спросить, в чем разница между этим и doThrow (new SomeException()).when(myObject).someMethod(any()) ;

2. один предназначен для макета, другой — для объекта-заглушки