英文:
Mockito doThrow() not throwing exception
问题
以下是您要翻译的内容:
已经有类似的问题,但这些问题都不能解决我当前的问题。
假设我有一个相当简单的类:
public class ClassA {
    private final Object someVariable;
    
    public ClassA(Object obj) {
        this.someVariable = obj;
    }
    public void Object someMethod(Object obj) throws SomeException {
    //做一些操作
    }
}
现在,在另一个类中创建了该类的一个实例:
public class ClassB {
    private final Object anotherVariable;
    public void Object anotherMethod() throws SomeException {
        try {
            ClassA objectA = new ClassA(anotherVariable);
            objectA.someMethod();
        } 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 void Test() throws Exception {     
    doThrow(new SomeException()).when(myObject).someMethod(any());
    when(myObject.someMethod(any())).thenThrow(new SomeException());
}
有关为什么这样会起作用的任何解释吗?这是不良实践吗?
英文:
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?
答案1
得分: 4
我相信原因是您从未调用该方法:
@Test(expected = SomeException.class)
public void myTest() throws Exception {
    // 在这里对方法进行存根
    doThrow(new SomeException()).when(myObject).someMethod(any());
    // 也可能应该是这样的:
    // doThrow(new SomeException()).when(myObject).someMethod();
    // 因为ClassA中的方法没有任何参数
    // 您需要在某个地方调用它
    // 您可以明确地这样做
    myObject.someMethod(/*也许在这里加入一些参数*/);
    // 或者您可以调用调用此方法的其他方法
    // 在模拟对象上 - 然后您也应该会得到异常
}
另外,ClassB中有一个小问题:
public void Object anotherMethod() throws SomeException {
    try {
        // 在这里实例化了ClassA类型的obj
        // 这意味着如果您需要测试anotherMethod(),则无法对其进行模拟
        ClassA objectA = new ClassA(anotherVariable)
        objectA.someMethod()
    } catch {
        // 做一些处理
    }
}
如果您想测试ClassB.anotherMethod(),您需要消除这种过于紧密的耦合:
public class ClassB {
    private final ClassA objectA;
    public ClassB(ClassA obj) {
        // 现在您可以提供ClassA的任何实例,而不是在try块中创建它
        // 因此,当您在实际代码中需要ClassB时,可以创建ClassA的某个真实实例并传递给此构造函数
        // 对于测试,您可以传递模拟对象
        this.objectA = obj;
    }
    public void Object anotherMethod() throws SomeException {
        try {
            objectA.someMethod()
        } catch {
            // 做一些处理
        }
    }
}
这样给我们带来的好处是:
@Mock
ClassA myObject = new ClassA(obj)
...
@Test(expected = SomeException.class)
public void myTest() throws Exception {
    // 在ClassA对象上存根someMethod
    doThrow(new SomeException()).when(myObject).someMethod();
    ClassB objB = new ClassB(myObject);
    
    // 现在您可以测试它,在anotherMethod()内部
    // 将在模拟上调用someMethod(),因此您将获得异常
    objB.anotherMethod();
}
英文:
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();
}
答案2
得分: 0
以下是翻译好的内容:
我假设你在下面一行嘲笑 Class A:
@Mock
ClassA myObject = new ClassA(obj); // 你创建了一个新实例
那么可以这样做:
使用 initMock 或者 @InjectMocks:
@Mock
ClassA myObject; // 假设你在使用 initMock 或 @InjectMocks
或者:
直接使用 Mockito 创建一个模拟实例:
ClassA myObject = Mockito.mock(ClassA.class);
然后,模拟方法调用的行为如下:
when(myObject.someMethod(any()))
      .thenThrow(new SomeException());
英文:
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());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论