【问题标题】:Mokito/Java - Static Methods MockMockito/Java - 静态方法模拟
【发布时间】:2022-01-03 17:09:57
【问题描述】:

例如,我有以下类:

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

   }
}

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

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

项目中的库版本:

  • junit-jupiter 5.5.2
  • mockito-junit-jupiter 3.2.14
  • mockito-inline 3.2.14

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

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

【问题讨论】:

  • 使用@BeforeAll-方法来初始化静态模拟,而不是在每个测试中初始化它。
  • @Lesiak Mockito.reset(Mockito.mockStatic(TesteEstatico.class)) 会是这样吗?

标签: java mockito


【解决方案1】:

您应该在每个测试中使用 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);
        }
    }
}

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

teste2 打印:

  • FOO BANANA BAR 如果在 teste1 之后运行
  • FOO null BAR 如果单独运行

这正是你想要避免的。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 这是个坏建议 - 测试不再是独立的
    猜你喜欢
    • 2022-01-11
    • 2014-08-30
    • 2014-02-02
    • 1970-01-01
    相关资源
    最近更新 更多