尝试模拟具有静态方法的类的示例不起作用

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

Example of trying to mock a Class that has a static method is not working

问题

我正在尝试学习如何使用Mockito,特别是我试图理解如何使静态方法的模拟工作。我正在使用Eclipse作为IDE,并找到了这个页面:https://www.testim.io/blog/mocking-static-methods-mockito/,并试图测试“选项#1:创建包装对象”中的示例。

因此,我已根据该文章创建了类和接口,并添加了“mockito-extensions”目录和包含字符串的“mockito-extensions/org.mockito.plugins.MockMaker”文件。但是当我尝试在Eclipse中运行测试(Run as Junit test)时,似乎执行了“StringCalculatorTest”类中的代码,但似乎并没有实际进入实现类和具有静态方法的原始类。

这是具有静态方法的类:

package mil.nga.geoaxis.orchestrator_spring.rest;

public class StringCalculatorStatic {

  public static int add(String numbers) {
      System.out.println("In StringCalculatorStatic: Entering...");
      String[] parts = numbers.split(",");
      int sum = 0;
      for (String part : parts) {
        int number = Integer.parseInt(part);
        sum += number;
      }
      System.out.println("In StringCalculatorStatic: sum=[" + sum + "]");
      return sum;
  } // end add()

}

这是接口:

package mil.nga.geoaxis.orchestrator_spring.rest;

public interface StringCalculator {
    
    public int add(String numbers);

}

以及实现类:

package mil.nga.geoaxis.orchestrator_spring.rest;

public class StringCalculatorImpl implements StringCalculator{
    @Override
    public int add(String numbers) {
        System.out.println("In StringCalculatorImp.add: Entering...");
        return StringCalculatorStatic.add(numbers);
    }

}

最后是测试类:

package mil.nga.geoaxis.orchestrator_spring.rest;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mockito;

public class StringCalculatorTest {
    
    @Test
    public void testAdd() {
        System.out.println("In StringCalculatorTest.testAdd: Entering...");
        System.out.println("In StringCalculatorTest.testAdd: About to create the mock of StringCalculator object...");
        StringCalculator calc = Mockito.mock(StringCalculator.class);
        System.out.println("In StringCalculatorTest.testAdd: Created the mock of StringCalculator object and reference stored in 'calc'");

        System.out.println("In StringCalculatorTest.testAdd: About to call calc() method...");
        int responseFromCallingCalc = calc.add("4,6");
        System.out.println("In StringCalculatorTest.testAdd: Returned from calling calc() method, responseFromCallingCalc=[" + responseFromCallingCalc + "]");
        
        Mockito.when(calc.add("4,6")).thenReturn(10);
        System.out.println("In StringCalculatorTest.testAdd FINISHED...");
    }

}

当我运行Junit时,输出如下:

In StringCalculatorTest.testAdd: Entering...
In StringCalculatorTest.testAdd: About to create the mock of StringCalculator object...
In StringCalculatorTest.testAdd: Created the mock of StringCalculator object and reference stored in 'calc'
In StringCalculatorTest.testAdd: About to call calc() method...
In StringCalculatorTest.testAdd: Returned from calling calc() method, responseFromCallingCalc=[0]
In StringCalculatorTest.testAdd FINISHED...

其他类的输出都没有显示,所以我猜想,出于某种原因,它实际上没有进行模拟。有人可以帮助/建议我遗漏了什么吗?

谢谢,
Jim

编辑:我编辑了测试类,添加了对“calc”的调用(根据Lesiak的建议以及一些额外的调试println),但看起来仍然只执行测试类中的代码,而没有执行StringCalculatorStatic类中的静态方法。

英文:

I am trying to learn about using Mockito and in particular I am trying to understand how mocking of static methods can be made to work. I am using Eclipse for the IDE, and I found this page:

https://www.testim.io/blog/mocking-static-methods-mockito/

and trying to test the example in "Option #1: Create Wrapper Objects".

So I have created the classes and interface per that article and I have added the "mockito-extensions" directory and the "mockito-extensions/org.mockito.plugins.MockMaker" file with the string in it, but then I try to run a test in Eclipse (Runas Junit test), it appears that it is executing the code in the "StringCalculatorTest" class but it doesn't appear to actually going into the implementation class and the original class with the static method.

Here is the class with the static method:

package mil.nga.geoaxis.orchestrator_spring.rest;

public class StringCalculatorStatic {
	
	  public static int add(String numbers) {
		  System.out.println("In StringCalculatorStatic: Entering...");
		    String[] parts = numbers.split(",");
		    int sum = 0;
		    for (String part : parts) {
		      int number = Integer.parseInt(part);
		      sum += number;
		    }
		    System.out.println("In StringCalculatorStatic: sum=[" + sum + "]");
		    return sum;
	  } // end add()

}

and here is the interface:

package mil.nga.geoaxis.orchestrator_spring.rest;

public interface StringCalculator {
	
	public int add(String numbers);

}

and the implementation class:

package mil.nga.geoaxis.orchestrator_spring.rest;

public class StringCalculatorImpl implements StringCalculator{
    @Override
    public int add(String numbers) {
    	System.out.println("In StringCalculatorImp.add: Entering...");
        return StringCalculatorStatic.add(numbers);
    }

}

and finally the class with the Test:

package mil.nga.geoaxis.orchestrator_spring.rest;


import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mockito;


public class StringCalculatorTest {
	
	
	@Test
	public void testAdd() {
		System.out.println("In StringCalculatorTest.testAdd: Entering...");
		System.out.println("In StringCalculatorTest.testAdd: About to create the mock of StringCalculator object...");
		StringCalculator calc = Mockito.mock(StringCalculator.class);
		System.out.println("In StringCalculatorTest.testAdd: Created the mock of StringCalculator object and reference stored in 'calc'");

		System.out.println("In StringCalculatorTest.testAdd: About to call calc() method...");
		int responseFromCallingCalc = calc.add("4,6");
		System.out.println("In StringCalculatorTest.testAdd: Returned from calling calc() method, responseFromCallingCalc=[" + responseFromCallingCalc + "]");
		
		Mockito.when(calc.add("4,6")).thenReturn(10);
		System.out.println("In StringCalculatorTest.testAdd FINISHED...");
	}

}

When I do RunAs Junit the output is:

In StringCalculatorTest.testAdd: Entering...
In StringCalculatorTest.testAdd: About to create the mock of StringCalculator object...
In StringCalculatorTest.testAdd: Created the mock of StringCalculator object and reference stored in 'calc'
In StringCalculatorTest.testAdd: About to call calc() method...
In StringCalculatorTest.testAdd: Returned from calling calc() method, responseFromCallingCalc=[0]
In StringCalculatorTest.testAdd FINISHED...

None of the output from the other classes is appearing, so I am guessing, that for some reason, it is not actually doing the mocking?

Can someone help/suggest what I am missing?

Thanks,
Jim

EDIT: I've edited the test class to add a call to 'calc' (per suggestion from Lesiak and also some additional debug printlns, but it looks like it is still only executing the Test class code and not execute the static method in the StringCalculatorStatic class.

答案1

得分: 1

我找到了这个页面:
https://www.testim.io/blog/mocking-static-methods-mockito/
并尝试测试“选项#1:创建包装对象”中的示例。

从该页面获取选项1的内容(重点是我的)

第一种选项是根本不模拟静态方法

所以...

其他类的输出都不会显示,所以我猜,由于某种原因,实际上并没有进行模拟?

有人可以帮助/建议我错过了什么吗?

你错过了你正在遵循的文章建议的一点,那就是你不需要模拟静态对象。它正在按照预期工作。而不是模拟静态函数,你创建一个包装类,只是调用静态函数。然后在你的测试中,你模拟包装类的实例,而不是模拟静态函数。

编辑:后续问题。

但我认为我正在做你说的吗?

是的,你是。这就是重点。你正在创建一个包装类来包装静态方法,而实际上并没有使用或模拟静态函数。

StringCalculatorImpl是StringCalculator接口的实现,在StringCalculatorTest中,我执行“StringCalculator calc = Mockito.mock(StringCalculator.class)”,也就是创建StringCalculator类的模拟实例。这不就是文章(以及你建议的“然后在你的测试中,你模拟包装类的实例,而不是模拟静态函数”)中提到的吗?

是的,是的。回到你的最初的问题:

其他类的输出都不会显示,所以我猜,由于某种原因,实际上并没有进行模拟?

根据你的问题和随后的回应,我认为你对模拟的工作原理有一些误解。你之所以看不到其他类的输出,恰恰是因为进行了模拟。

让我们来复习一下:

StringCalculator calc = Mockito.mock(StringCalculator.class);

这是你定义的接口的模拟。它已经存根化了什么都不做的方法。因此,你的StringCalculatorImpl中的真正add方法永远不会被调用,当你执行:

int responseFromCallingCalc = calc.add("4,6");

而且,因为你没有告诉Mockito在调用该模拟对象的方法时要做什么,所以你将得到默认值(0)。

接下来,你指示Mockito在给定特定输入时返回特定值。然而,在这之后,你在示例中没有执行其他操作,所以这种模拟是没有意义的:

Mockito.when(calc.add("4,6")).thenReturn(10);

在这一点上,如果你获取calc.add("4,6")的值,它将返回10,正如你告诉它的一样。再次强调,因为你在使用模拟,所以你的实际代码都不会被执行。

如果这还不清楚,那么我的最佳建议是在网上搜索并阅读关于Mockito工作原理的教程或示例。

英文:

> I found this page:
https://www.testim.io/blog/mocking-static-methods-mockito/
and trying to test the example in "Option #1: Create Wrapper Objects".

From that page for option 1 (emphasis mine)

> The first option consists of not mocking the static method at all.

So ...
> None of the output from the other classes is appearing, so I am guessing, that for some reason, it is not actually doing the mocking?

> Can someone help/suggest what I am missing?

You're missing the fact that the article you're following is suggesting a way that you do not mock a static object. It's working exactly as intended. Instead of mocking a static function, you create a wrapper class that just calls the static function. Then in your tests your mock instances of the wrapper class instead of mocking the static functions.

EDIT: Follow up question.

> But I think I AM doing what you said?

Yes, you are. That's the point. You are creating a wrapper around the static and never actually using or mocking the static functions.

> StringCalculatorImpl is the implementation of StringCalculator interface, and in StringCalculatorTest, I do "StringCalculator calc = Mockito.mock(StringCalculator.class)", i.e. create a mock instance of the StringCalculator class. Isn't that what the article (and what you suggested ("Then in your tests your mock instances of the wrapper class instead of mocking the static functions")?

Yes, it is. Going back to your original question:

> None of the output from the other classes is appearing, so I am guessing, that for some reason, it is not actually doing the mocking?

Based on your question and subsequent responses, I think you have a misunderstanding of how mocks work. You are not seeing output from the other classes precisely because it is doing the mocking.

Let's review:

StringCalculator calc = Mockito.mock(StringCalculator.class);

This is a mock of the interface you've defined. It has stubbed out methods that do nothing. Therefore, your real add method in StringCalculatorImpl will never be called and you will never see a print statement when you do:

int responseFromCallingCalc = calc.add("4,6");

And, because you've not told Mockito what to do when calling that method on that mock, you will get back a default value (0).

Next you instructed Mockito to return a specific value given specific inputs. However, you do nothing else with this mock after this, so this mocking is pointless in your example:

Mockito.when(calc.add("4,6")).thenReturn(10);

At this point, if you were to get the value of calc.add("4,6"), it would return 10, as you told it to. Again - none of your actual code gets executed because you're working with a mock.

If this is still unclear, then my best advice would be to Google around for and read through tutorials or examples of how Mockito works.

huangapple
  • 本文由 发表于 2023年3月10日 01:49:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75688299.html
匿名

发表评论

匿名网友

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

确定