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

单例对象的Spy正在调用JUnit中的真实方法,并且在为Mocked对象一起运行所有测试时,方法模拟不起作用

宗政兴发
2023-03-14

我有两个单身班

   public class Singleton1 {

    private static Singleton1 INSTANCE = null;

    private final Singleton2 singleton2;

    private Singleton1(Singleton2 singleton2){
      this.singleton2 = singleton2;
    }

    public static Singleton1 getInstance(Singleton2 singleton2) {
        if(INSTANCE == null) {
            synchronized (Singleton1.class) {
                INSTANCE = new Singleton1(singleton2);
            }
        }
      return INSTANCE;
    }
    
    public String getOutput(String input) {
      switch(input) {
        case "CONNECT" : return "Connected";
        case "PING" : return singleton2.getPingResponse(input);
        default: return "nevermind";
      }
    }

   }

单人二等舱

   public class Singleton2 {

    private static Singleton2 INSTANCE = null;
    private Singleton2(){
    }

    public static Singleton2 getInstance() {
        if(INSTANCE == null) {
            synchronized (Singleton1.class) {
                INSTANCE = new Singleton2();
            }
        }
        return INSTANCE;
    }

    public  String getPingResponse(String s) {
        System.out.println("CALLING HERE");
        if(s.contains("CON")) {
            return "connected";
        } else {
            return "OK";
        }
     }
   }

测试类别

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class Singleton1Test { // if running all tests together then the mocking is not happening

    Singleton2 s2 = Mockito.mock(Singleton2.class);
//    Singleton2 s2 = Mockito.mock(Singleton2.class);
//    Singleton2 spiedS2 = Mockito.spy(s2); // if I use spying it will call real method
    Singleton1 s1 = Singleton1.getInstance(s2);

    @Test // this test alone is fine
    public void TestConnect() {
        Assertions.assertEquals("Connected", s1.getOutput("CONNECT"));
    }

    @Test // this test alone is fine
    public void TestPing() {
        // mock will work when I run this test alone
        Mockito.doReturn("OK").when(s2).getPingResponse(anyString());
        // this is calling real method from singleton2 object
//        Mockito.doReturn("OK").when(spiedS2).getPingResponse(anyString());
        Assertions.assertEquals("OK", s1.getOutput("PING"));
    }
}

如何为singleton1类执行适当的JUNIT,我不想在运行singleton1时从Singleton2执行任何方法。我试着刺探和嘲弄。当我在监视时,真正的方法是被调用。当我模拟Singleton2时,由于模拟调用问题,所有测试运行都失败了。

如果我错了,请告诉我

共有2个答案

陆晓博
2023-03-14

经过几次搜索后,我通过两个注释修复了它。现在,我可以一起运行所有测试而不会出错。我将S2重命名为真实S1的属性名称。因此@InjectMock将毫无歧义地工作。大多数情况下,@InjectMock将通过setter或构造函数注入工作。这里我的构造函数是私有的,但它对我有用。

   @ExtendWith(MockitoExtension.class)
class SingletonTest {

    @Mock
    Singleton2 singleton2;

    @InjectMocks
    Singleton1 s1;

    @Test // this test alone is fine
    public void TestConnect() {
        Assertions.assertEquals("Connected", s1.getOutput("CONNECT"));
    }

    @Test // this test alone is fine
    void ping() {
        Mockito.doReturn("OK").when(singleton2).getPingResponse(anyString());
        Assertions.assertEquals("OK", s1.getOutput("PING"));
    }
}
赫连宏伯
2023-03-14

Spy正在处理实例。

 Singleton2 s2 = Singleton2.getInstance();

Mock不需要任何Singleton2实例来模拟它。

我取了你的代码,稍微修改了一下测试(小写的start方法名称,将anyString()更改为ArgumentMatchers.any(String.class))并对其进行了测试。对我来说,它工作正常。我使用的是Junit5.7.1和Mockito 3.8.0。由于测试ping方法对您来说失败了,我没有在我的示例中插入测试连接。

我认为您的错误是混淆了Mock和Spy,而没有使用Singleton2的实例。让我向您展示。

我使用以下导入的示例

import static org.mockito.ArgumentMatchers.any;

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

您的代码使用Mock和Spy Singleton2(我根据您的注释进行假设)

@ExtendWith(MockitoExtension.class)
class SingletonTest {

//  Singleton2 s2 = Singleton2.getInstance();
    Singleton2 s2 = Mockito.mock(Singleton2.class);
    Singleton2 spiedS2 = Mockito.spy(s2); // if I use spying it will call real method
    Singleton1 s1 = Singleton1.getInstance(s2);

    @Test // this test alone is fine
    void ping() {
        // mock will work when I run this test alone
        // Mockito.doReturn("OK").when(s2).getPingResponse(any(String.class));
        // this is calling real method from singleton2 object
        Mockito.doReturn("OK").when(spiedS2).getPingResponse(any(String.class));
        Assertions.assertEquals("OK", s1.getOutput("PING"));
    }
}

结果在

org.opentest4j.AssertionFailedError: expected: <OK> but was: <null>
    at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
    ...

仅在Singleton2上使用带有实例的间谍

@ExtendWith(MockitoExtension.class)
class SingletonTest {

    Singleton2 s2 = Singleton2.getInstance();
//  Singleton2 s2 = Mockito.mock(Singleton2.class);
    Singleton2 spiedS2 = Mockito.spy(s2);
    Singleton1 s1 = Singleton1.getInstance(spiedS2);

    @Test // this test alone is fine
    void ping() {
        // Mockito.doReturn("OK").when(s2).getPingResponse(any(String.class));
        Mockito.doReturn("OK").when(spiedS2).getPingResponse(any(String.class));
        Assertions.assertEquals("OK", s1.getOutput("PING"));
    }
}

顺利通过测试。如果您使用

    Singleton1 s1 = Singleton1.getInstance(s2);

仅在没有实例的Singleton2上使用Mock

@ExtendWith(MockitoExtension.class)
class SingletonTest {

    Singleton2 s2 = Mockito.mock(Singleton2.class);
//  Singleton2 s2 = Singleton2.getInstance();
//  Singleton2 spiedS2 = Mockito.spy(s2);
    Singleton1 s1 = Singleton1.getInstance(s2);

    @Test // this test alone is fine
    void ping() {
        Mockito.doReturn("OK").when(s2).getPingResponse(any(String.class));
        // Mockito.doReturn("OK").when(spiedS2).getPingResponse(any(String.class));
        Assertions.assertEquals("OK", s1.getOutput("PING"));
    }
}

还顺利通过了测试。

根据第二个答复作出的补充

您还可以通过注释定义Mock。(我之前没有使用它们,因为示例代码没有使用它们。)

@Mock
Singleton2 singleton2;

@InjectMocks
Singleton1 s1;
 类似资料:
  • 我有一个测试,如下所示,在给定条件下,我想确保。 然而,它错误地指出 错误出现在行 应为不是模拟对象。如何测试为非模拟对象调用的方法? 我在如何验证一个非模拟对象的方法中看到了答案?,但这仍然是使用模拟和间谍。我希望找到一种不需要嘲笑我已经拥有的类实例的方法。 (注:以上内容以科特林书写)

  • 我是Java初学者。我想在运行的Java线程对象中调用一个方法。它总是引发以下异常: 线程“AWT-EventQueue-0”java中出现异常。lang.NullPointerException:无法调用“Graphic\u handler.next()”,因为“this.this$0.grap”为null (代码已简化) 下面是我调用该方法的代码部分: 我试图在这里调用方法Next()和las

  • 好的,我有一个我正在创建的小程序叫做移动电话。它有三个类:Main.java、Contact.java和MobilePhone.java. 主要的java使用扫描器执行静态方法,通过电话菜单显示和返回信息。联系java是一个简单的类,它将姓名和号码存储为联系人。手机。java有as ArrayList,它将Contact类中的对象存储为contacts,然后有几个方法,比如addContact()

  • 我想在JUnit中创建用于测试运行的自定义html报告。我有一个问题是释放资源和关闭标记后,所有的测试都完成了。 我保留了一个打开的文件,以便编写报告。因为每个测试都应该是表和行,而且有数百个,所以我不想为每个测试打开和关闭通道。这里出现的问题是测试组织--我有嵌套的套件,所以testRunFinished不是一个选项(指单个套件,不是所有测试,我看到了这个问题)。TestWatcher也不会帮助

  • 下面是我要为其创建测试的类和方法: 具体地说,我希望模拟getAnalytics.getAll(),这样它就会返回一个我已经定义的字符串。而不是方法执行它的任务。这是我的代码:

  • 所以我有一个名为Tile的超类和许多子类,如BlueTile,GreenTile等。 不同子类的所有实例都存储在ArrayList中(例如(blueTile1、blueTile2、greenTile1……)。 在超类中有一个名为“activateTile()”的方法,所有子类都以不同的方式使用它。 现在,当我在阵列中循环并用blueTile激活所有蓝色Tile时。它们会一个接一个地被激活,对吗?