当前位置: 首页 > 知识库问答 >
问题:

Mokito/Java-静态方法模拟

范修伟
2023-03-14

例如,我有以下课程:

public class TesteEstatico {

   public static String teste(){
      return "FOO";
   }

}

我有一个类使用她的方法:

public class UsaTesteEstatico {

   public String metodoParaTeste1 (){
       return  TesteEstatico.teste() + " BAR ";
   }

   public String metodoParaTeste2 (){
       return  "FOO "+TesteEstatico.teste() + " BAR ";
   }

}

测试等级:

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

@ExtendWith(MockitoExtension.class) public class UsaTesteEstaticoTest {

   @InjectMocks
   UsaTesteEstatico usaTesteEstatico;

   @Test
   void teste1(){
       Mockito.mockStatic(TesteEstatico.class);
       Mockito.when(TesteEstatico.teste())
            .thenReturn("BANANA");

       String res = usaTesteEstatico.metodoParaTeste1();
       System.out.println(res);
   }

   @Test
   void teste2(){
       Mockito.mockStatic(TesteEstatico.class);
       Mockito.when(TesteEstatico.teste())
            .thenReturn("LARANJA");

       String res = usaTesteEstatico.metodoParaTeste2();
       System.out.println(res);

   }
}

尝试运行测试时遇到的错误:

组织。莫基托。例外情况。基础MockitoException:对于TesteStatico,静态模拟已在当前线程中注册以创建新的模拟,必须取消注册现有的静态模拟注册

项目中LIB的版本:

  • junit-jupiter 5.5.2
  • mockito-junit-jupiter 3.2.14
  • mockito-内联3.2.14

我尝试了一些方法,但都没有成功。

注意:我不能更改或添加任何新库,因为它是受限制的项目。

共有2个答案

苍恩
2023-03-14

您需要使用静态块来模拟它。

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


@ExtendWith(MockitoExtension.class)
public class UsaTesteEstaticoTest {
    @InjectMocks
    UsaTesteEstatico usaTesteEstatico;

    @BeforeAll
    public static void init(){
        Mockito.mockStatic(TesteEstatico.class);
    }

    @Test
    void teste1(){

        Mockito.when(TesteEstatico.teste())
                .thenReturn("BANANA");

        String res = usaTesteEstatico.metodoParaTeste1();
        System.out.println(res);
    }

    @Test
    void teste2(){

        Mockito.when(TesteEstatico.teste())
                .thenReturn("LARANJA");

        String res = usaTesteEstatico.metodoParaTeste2();
        System.out.println(res);

    }
}
翁宏茂
2023-03-14

您应该在每个测试中使用try-with-资源块来关闭mockStatic。

public class UsaTesteEstaticoTest {
    
    UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();

    @Test
    void teste1(){
        try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
            Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
            String res = usaTesteEstatico.metodoParaTeste1();
            System.out.println(res);
        }
    }

    @Test
    void teste2(){
        try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
            Mockito.when(TesteEstatico.teste()).thenReturn("LARANJA");
            String res = usaTesteEstatico.metodoParaTeste2();
            System.out.println(res);
        }
    }
}

关于@BeforeAll中mockStatic的注释

事先使用是一个陷阱和错误的建议。你应该努力进行相互不影响的独立测试。对于在@BeforeAll中调用的mockStatic,情况并非如此,因为测试方法的存根比测试方法更有效。

例如

// BAD CODE DONT USE
public class UsaTesteEstaticoTest {

    UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
    static MockedStatic<TesteEstatico> ms;

    @BeforeAll
    public static void init() {
        ms = Mockito.mockStatic(TesteEstatico.class);
    }

    @AfterAll
    public static void close() {
        ms.close();
    }


    @Test
    void teste1() {
        Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
        String res = usaTesteEstatico.metodoParaTeste1();
        System.out.println(res);
    }

    @Test
    void teste2() {
        String res = usaTesteEstatico.metodoParaTeste2();
        System.out.println(res);
    }
}

测试2打印:

  • 如果在测试1之后运行,请使用香蕉棒
  • 如果单独运行,则显示空栏

这正是你想要避免的。

 类似资料:
  • 问题内容: 我已经写了一家工厂来生产物体: 我想验证传递给的参数,但不知道如何模拟静态方法。我在测试用例中使用的是和。有没有模拟或验证此特定用例的好方法? 问题答案: 在Mockito上使用PowerMockito。 示例代码:

  • 问题内容: 我的代码中有一个静态方法,希望以某种方式进行模拟。 我正在使用jmock。 我想可以做到这一点的一种方法是在静态方法周围设置“包装类”并模拟该方法,但是我希望有一个更好的解决方案。 我要用这种错误的方式? 反馈: 我将要有一个接口和一个类,该接口和类具有一个仅称为静态方法的方法。这将允许我通过仅模拟对此包装器类的调用来模拟逻辑。(即使谈论它我也觉得很脏:)) 问题答案: 我们不支持在j

  • 问题内容: 我有一个类,我正在为应该执行以下操作的方法编写测试: 1)它应该调用静态方法上 2)它应该从子类方法填充变量 3)它应该从传递String参数的最终帮助器类中调用静态方法 4)它应该在blockList中调用每个的run方法 到目前为止,我有这个空方法: 我正在使用JUnit,Mockito来模拟对象,并且尝试使用PowerMockito来模拟静态类和最终类(Mockito不能这样做)

  • 我在一个类中有一个静态方法。方法不是最终的。我一直得到一个when()需要一个参数,该参数必须是'a method call on a mock‘错误。下面是我的代码。

  • 在安装到AEM 5.6.1实例之前,我正在使用maven构建和测试我的代码。我已经编写了单元测试,这些测试使用wcm的实现从aem模拟中获益。io和其他需要使用powermockito模拟静态方法的单元测试。 以下是我对aem上下文、sling Mock和powermock的maven依赖关系。 在我的课堂上,我正在为aem上下文设置规则,并准备一些用于模拟的静态类: 当我通过命令行运行mvn测试

  • 问题内容: 我在这里阅读了一些有关静态方法的主题,我认为我理解滥用/过度使用静态方法可能导致的问题。但是我并没有真正理解为什么很难模拟静态方法的原因。 我知道其他模拟框架(例如PowerMock)可以做到这一点,但为什么Mockito不能? 问题答案: 我认为原因可能是模拟对象库通常通过在运行时动态创建类(使用cglib)来创建模拟。这意味着他们要么在运行时实现一个接口(如果我没有记错的话,这就是