Mockito的doThrow()未抛出异常。

huangapple go评论96阅读模式
英文:

Mockito doThrow() not throwing exception

问题

以下是您要翻译的内容:

已经有类似的问题,但这些问题都不能解决我当前的问题。

假设我有一个相当简单的类:

  1. public class ClassA {
  2. private final Object someVariable;
  3. public ClassA(Object obj) {
  4. this.someVariable = obj;
  5. }
  6. public void Object someMethod(Object obj) throws SomeException {
  7. //做一些操作
  8. }
  9. }

现在,在另一个类中创建了该类的一个实例:

  1. public class ClassB {
  2. private final Object anotherVariable;
  3. public void Object anotherMethod() throws SomeException {
  4. try {
  5. ClassA objectA = new ClassA(anotherVariable);
  6. objectA.someMethod();
  7. } catch {
  8. //做一些操作
  9. }
  10. }
  11. }

最终目标是通过抛出异常来测试捕获的代码块,如下所示:

  1. @Mock
  2. ClassA myObject = new ClassA(obj);
  3. ...
  4. @Test(expected = SomeException.class)
  5. public void myTest()throws Exception {
  6. doThrow(new SomeException()).when(myObject).someMethod(any());
  7. }

由于某种原因,异常根本没有被抛出。我还尝试过用有效和无效的对象替换any(),但仍然不起作用。

编辑1:

在寻找解决方案时,以下代码不知何故通过了测试:

  1. @Test(expected = SomeException.class)
  2. public void Test() throws Exception {
  3. doThrow(new SomeException()).when(myObject).someMethod(any());
  4. when(myObject.someMethod(any())).thenThrow(new SomeException());
  5. }

有关为什么这样会起作用的任何解释吗?这是不良实践吗?

英文:

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

Say I have a fairly simple class:

  1. public class ClassA {
  2. private final Object someVariable;
  3. public classA(Object obj) {
  4. this.someVariable = obj
  5. }
  6. public void Object someMethod(Object obj) throws SomeException {
  7. //does stuff
  8. }
  9. }

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

  1. public class ClassB {
  2. private final Object anotherVariable;
  3. public void Object anotherMethod() throws SomeException {
  4. try {
  5. ClassA objectA = new ClassA(anotherVariable)
  6. objectA.someMethod()
  7. } catch {
  8. // does stuff
  9. }
  10. }
  11. }

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

  1. @Mock
  2. ClassA myObject = new ClassA(obj)
  3. ...
  4. @Test(expected = SomeException.class)
  5. public void myTest()throws Exception {
  6. doThrow(new SomeException()).when(myObject).someMethod(any());
  7. }

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:

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

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

答案1

得分: 4

我相信原因是您从未调用该方法:

  1. @Test(expected = SomeException.class)
  2. public void myTest() throws Exception {
  3. // 在这里对方法进行存根
  4. doThrow(new SomeException()).when(myObject).someMethod(any());
  5. // 也可能应该是这样的:
  6. // doThrow(new SomeException()).when(myObject).someMethod();
  7. // 因为ClassA中的方法没有任何参数
  8. // 您需要在某个地方调用它
  9. // 您可以明确地这样做
  10. myObject.someMethod(/*也许在这里加入一些参数*/);
  11. // 或者您可以调用调用此方法的其他方法
  12. // 在模拟对象上 - 然后您也应该会得到异常
  13. }

另外,ClassB中有一个小问题:

  1. public void Object anotherMethod() throws SomeException {
  2. try {
  3. // 在这里实例化了ClassA类型的obj
  4. // 这意味着如果您需要测试anotherMethod(),则无法对其进行模拟
  5. ClassA objectA = new ClassA(anotherVariable)
  6. objectA.someMethod()
  7. } catch {
  8. // 做一些处理
  9. }
  10. }

如果您想测试ClassB.anotherMethod(),您需要消除这种过于紧密的耦合:

  1. public class ClassB {
  2. private final ClassA objectA;
  3. public ClassB(ClassA obj) {
  4. // 现在您可以提供ClassA的任何实例,而不是在try块中创建它
  5. // 因此,当您在实际代码中需要ClassB时,可以创建ClassA的某个真实实例并传递给此构造函数
  6. // 对于测试,您可以传递模拟对象
  7. this.objectA = obj;
  8. }
  9. public void Object anotherMethod() throws SomeException {
  10. try {
  11. objectA.someMethod()
  12. } catch {
  13. // 做一些处理
  14. }
  15. }
  16. }

这样给我们带来的好处是:

  1. @Mock
  2. ClassA myObject = new ClassA(obj)
  3. ...
  4. @Test(expected = SomeException.class)
  5. public void myTest() throws Exception {
  6. // 在ClassA对象上存根someMethod
  7. doThrow(new SomeException()).when(myObject).someMethod();
  8. ClassB objB = new ClassB(myObject);
  9. // 现在您可以测试它,在anotherMethod()内部
  10. // 将在模拟上调用someMethod(),因此您将获得异常
  11. objB.anotherMethod();
  12. }
英文:

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

  1. @Test(expected = SomeException.class)
  2. public void myTest(0 throws Exception {
  3. // here you stub the method
  4. doThrow(new SomeException()).when(myObject).someMethod(any());
  5. // also it should probably be like this:
  6. // doThrow(new SomeException()).when(myObject).someMethod();
  7. // because the method in ClassA does not have any params
  8. // you need it to be called somewhere
  9. // you can do that explicitly
  10. myObject.someMethod(/*perhaps some param here*/);
  11. // or you can call some other method which calls this one
  12. // on the mock - then you should get an exception as well
  13. }

Also, there is a little issue in ClassB:

  1. public void Object anotherMethod() throws SomeException {
  2. try {
  3. // you instantiate obj of type ClassA here
  4. // which means you cannot mock it if you need
  5. // to test anotherMethod()
  6. ClassA objectA = new ClassA(anotherVariable)
  7. objectA.someMethod()
  8. } catch {
  9. // does stuff
  10. }
  11. }

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

  1. ClassA objectA = new ClassA(anotherVariable)

Consider approach like this:

  1. public class ClassB {
  2. private final ClassA objectA;
  3. public ClassB(ClassA obj) {
  4. // now you can provide any instance of ClassA instead
  5. // of having it created in try-block later
  6. // so when you need ClassB in real code, you can create
  7. // some real instance of ClassA and pass to this conctructor
  8. // and for test you can pass mock
  9. this.objectA = obj;
  10. }
  11. public void Object anotherMethod() throws SomeException {
  12. try {
  13. objectA.someMethod()
  14. } catch {
  15. // does stuff
  16. }
  17. }
  18. }

What this gives us:

  1. @Mock
  2. ClassA myObject = new ClassA(obj)
  3. ...
  4. @Test(expected = SomeException.class)
  5. public void myTest()throws Exception {
  6. // stub someMethod on object of ClassA
  7. doThrow(new SomeException()).when(myObject).someMethod();
  8. ClassB objB = new ClassB(myObject);
  9. // now you can test it, and inside anotherMethod()
  10. // there will be a call to someMethod() on a mock
  11. // so you will get an exception
  12. objB.anotherMethod();
  13. }

答案2

得分: 0

以下是翻译好的内容:

我假设你在下面一行嘲笑 Class A:

  1. @Mock
  2. ClassA myObject = new ClassA(obj); // 你创建了一个新实例

那么可以这样做:

使用 initMock 或者 @InjectMocks

  1. @Mock
  2. ClassA myObject; // 假设你在使用 initMock 或 @InjectMocks

或者:

直接使用 Mockito 创建一个模拟实例:

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

然后,模拟方法调用的行为如下:

  1. when(myObject.someMethod(any()))
  2. .thenThrow(new SomeException());
英文:

I assume since u are mocking Class A below line

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

do

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

or

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

then Mock the behavior how u mock a method call

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

huangapple
  • 本文由 发表于 2020年10月9日 03:46:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/64269629.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定