Mokito/Java - 静态方法模拟

cla*_*san 2 java mockito

例如我有以下课程:

public class TesteEstatico {

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

}
Run Code Online (Sandbox Code Playgroud)

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

public class UsaTesteEstatico {

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

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

}
Run Code Online (Sandbox Code Playgroud)

测试类:

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);

   }
}
Run Code Online (Sandbox Code Playgroud)

尝试运行测试时出现错误:

org.mockito.exceptions.base.MockitoException:对于 TesteEstatico,静态模拟已经在当前线程中注册要创建新的模拟,必须取消注册现有的静态模拟注册

项目中的库版本:

  • junit-木星 5.5.2
  • 模拟-junit-木星 3.2.14
  • 模拟内联 3.2.14

知道如何解决这个问题,我尝试了一些方法,但没有成功。

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

Les*_*iak 7

您应该在每个测试中使用 try-with-resources 块来关闭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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

关于@BeforeAll中的mockStatic的注意事项

使用@BeforeAll是一个陷阱和不好的建议。您应该努力进行互不影响的独立测试。@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

teste2印刷:

  • FOO BANANA BAR如果追赶teste1
  • FOO null BAR如果单独运行

这正是您想要避免的。