如何正确在类中模拟全局对象?

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

How to mock a global object in a class properly?

问题

让我们假设我有一个如下所示的类:

Class A{
   private K Obj = (K)(AppContext.getSpringContext().getBean("obj"))
   
  public void method1{
     // 使用 Obj
  }

  public void method2{
    // 使用 Obj
  }

}

我需要为method1和method2编写Junit测试,并在method1和method2中更改Obj的行为。在我的Junit类中,我设置了appcontext如下:

public class AccountInformationManagerTest {

    private CCBSAppContext appContext;

    @Mock
    ApplicationContext springContext;
     
    @Mock
    Object obj;

   @Before
    public void setup() throws Exception {
        appContext = new CCBSAppContext();
        appContext.setApplicationContext(springContext);
        Mockito.when(springContext.getBean("obj")).thenReturn(obj);
    }
}

正如你所看到的,我全局设置了appcontext。我不想模拟静态调用,因为我正在使用jacoco,而powermockito与jacoco不太兼容。问题在于appcontext现在是一个全局对象,它在所有方法之间共享,并且我需要在测试这两个方法时修改obj的行为。这将创建并发问题。我该如何解决这个问题?

英文:

Let say I have a class like so

Class A{
   private K Obj = (K)(AppContext.getSpringContext().getBean("obj"))
   
  public void method1{
     // uses Obj
  }

  public void method2{
    // uses Obj
  }

}

And I need to write junits for method1 and method2 by changing the behavior of Obj in method 1 and method 2. In my junit class I am setting the appcontext as so:

public class AccountInformationManagerTest {

    private CCBSAppContext appContext;

    @Mock
    ApplicationContext springContext;
     
    @Mock
    Object obj;

   @Before
    public void setup() throws Exception {
        appContext = new CCBSAppContext();
        appContext.setApplicationContext(springContext);
        Mockito.when(springContext.getBean("obj")).thenReturn(obj);
    }
}

As you can see, I am setting globally the appcontext. I don't want mock the static calls as I am using jacoco and powermockito doesn't integrate very well with jacoco. The problem here is that appcontext is now a global object which is shared across all methods and I need to modify the behavior of obj as I test the two methods. This will create a concurrency issue. How can I resolve this?

答案1

得分: 1

避免直接使用 (K)(AppContext.getSpringContext().getBean("obj")) 来注入依赖项,而应通过自动装配或自动注入的方式添加依赖项。然后可以通过 SpringTestUtils 或设置器(setters)轻松进行测试并向类中添加 obj。

@Autowired
K obj;

否则,您可以为每个测试模拟 springContext 的 getBean 方法。

@Test
void fun {
     Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj);
     // 进行某些操作
}

@Test
void fun2 {
     Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj2);
     // 进行某些操作2
}
英文:

TBH avoid (K)(AppContext.getSpringContext().getBean("obj")) directly inject dependency or autowire the dependency . Then in its easily testable and add obj to the class via SpringTestUtils or setters.

@Autowired
K obj;

Else you can mock springContext getBean method for every test

@Test
void fun {
     Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj);
     // doSomething
}


@Test
void fun2 {
     Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj2);
     // doSomething2
}

答案2

得分: 1

使用反射来设置Obj。然后,您可以将Obj设置为一个模拟对象。

这里有一个描述如何做到这一点的Stack Overflow答案。

英文:

Use reflection to set the Obj. Then you can set Obj to be a mocked object.

Here is a SO answer describing how to do it.

huangapple
  • 本文由 发表于 2020年7月31日 00:58:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63177920.html
匿名

发表评论

匿名网友

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

确定