Java 单元测试时如何跳过@PostConstruct

Java 单元测试时如何跳过@PostConstruct,java,spring,junit4,postconstruct,Java,Spring,Junit4,Postconstruct,我有一个每天晚上收集数据的计划任务。每当我启动应用程序时,任务就会运行,当我在应用程序上运行jUnit测试时,我想停止它的运行 @Scheduled(cron = "0 0 0 1 * ?") public void SalesDataAggregation() { //aggregation } 编辑 上面的方法也在这里被调用 @PostConstruct public void init(){ SalesDataAggregation(); } 由于@PostConstr

我有一个每天晚上收集数据的计划任务。每当我启动应用程序时,任务就会运行,当我在应用程序上运行jUnit测试时,我想停止它的运行

@Scheduled(cron = "0 0 0 1 * ?")
public void SalesDataAggregation() {
    //aggregation
}
编辑

上面的方法也在这里被调用

@PostConstruct
public void init(){
    SalesDataAggregation();
}

由于@PostConstruct注释,方法SalesDataAggregate在启动时运行。如果希望在测试期间不让它运行,可以在测试文件夹中创建包含post构造的类,并添加@primary注释,使其优先于主项目中的类

@Primary
public class ClassContainingPostConstruct{   

}

由于@PostConstruct注释,方法SalesDataAggregate在启动时运行。如果希望在测试期间不让它运行,可以在测试文件夹中创建包含post构造的类,并添加@primary注释,使其优先于主项目中的类

@Primary
public class ClassContainingPostConstruct{   

}

您可以将包含bean的
PostConstruct
重新写入
EventListener
()以在启动时触发,我认为这就是本文的目的。然后,该bean可以绑定到特定的
配置文件
,以仅在特定启用的配置文件上触发

另一种选择是使用属性有条件地触发它

public class PostConstructBean {

public boolean isPostConstructEnabled;

public PostConstructBean(@Value("${postconstructenabled}" String value){
   isPostConstructEnabled = Boolean.parseBoolean(value);
}

@PostConstruct
public void init(){
   if(isPostConstructEnabled){
      SalesDataAggregation();
   }else{
      //NOOP
   }
}
}

然后只需将属性添加到环境属性/总体属性文件中。这增加了允许您更轻松地加载/禁用bean的好处,您可以将包含bean的
PostConstruct
重新写入
EventListener
()以在启动时触发,我假设这就是它的目的。然后,该bean可以绑定到特定的
配置文件
,以仅在特定启用的配置文件上触发

另一种选择是使用属性有条件地触发它

public class PostConstructBean {

public boolean isPostConstructEnabled;

public PostConstructBean(@Value("${postconstructenabled}" String value){
   isPostConstructEnabled = Boolean.parseBoolean(value);
}

@PostConstruct
public void init(){
   if(isPostConstructEnabled){
      SalesDataAggregation();
   }else{
      //NOOP
   }
}
}

然后只需将属性添加到环境属性/总体属性文件中。这增加了允许您更轻松地加载/禁用bean的好处

在我的情况下,我的PostConstruct中没有任何内容会使我的其他测试崩溃,只有我的Mockito.verify,因此我决定保留PostConstruct使用的注入的mock类,然后在我的测试中,使用Mockito和ReflectionTestUtils重新模拟并重新注入它。这避免了bean创建的问题,并允许我只验证新模拟的类:

测试类别:

@Component
public class ClassUnderTest
{
    @Autowired
    private MockedClass nameOfActualBeanInClassUnderTest;

    @PostConstruct
    private void postConstructMethod()
    {
        Object param1 = new Object();
        Object param2 = new Object();
        this.nameOfActualBeanInClassUnderTest.mockedClassFunctionBeingHit(param1, param2);
    }
}
测试类别:

import static org.mockito.Mockito.*;
import org.springframework.test.util.ReflectionTestUtils;

public class Tests
{
    // Class Under Test
    @Autowired
    private ClassUnderTest classUnderTest;

    // Mocked Class
    @MockBean
    private MockedClass mockedClass;

    @Test
    public void actualTestThatAvoidsPostConstruct()
    {
        // ============== Ignore PostConstruct Errors ==============

        // Note: You will probably want to capture the current mocked class
        // to put it back in the class under test so that other tests won't fail
        MockedClass savedMockedClass = 
        (MockedClass)ReflectionTestUtils.getField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest");

        this.mockedClass = mock(MockedClass.class);
        ReflectionTestUtils.setField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest",
            this.mockedClass);

        // ============== Setup Test ==============
        Object response = new Object();

        // Set return value when mockedClass' function is hit
        // Note: Only need to pass params if your function actually has them
        when(this.mockedClass.mockedClassFunctionBeingHit(param1, param2))
            .thenReturn(response);

        // ============== Test ==============

        this.classUnderTest.testFunction();

        // ============== Verify ==============

        // Note: Only need to pass params if your function actually has them
        verify(this.mockedClass).mockedClassFunctionBeingHit(param1, param2);

        // ============== Reset Mocked Class ==============
        ReflectionTestUtils.setField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest",
            savedMockedClass);
    }
}

在我的例子中,PostConstruct中没有任何内容会使我的其他测试崩溃,只有Mockito.verify,因此我决定保留PostConstruct使用的注入的mock类,然后在我的测试中,使用Mockito和ReflectionTestUtils重新模拟和注入它。这避免了bean创建的问题,并允许我只验证新模拟的类:

测试类别:

@Component
public class ClassUnderTest
{
    @Autowired
    private MockedClass nameOfActualBeanInClassUnderTest;

    @PostConstruct
    private void postConstructMethod()
    {
        Object param1 = new Object();
        Object param2 = new Object();
        this.nameOfActualBeanInClassUnderTest.mockedClassFunctionBeingHit(param1, param2);
    }
}
测试类别:

import static org.mockito.Mockito.*;
import org.springframework.test.util.ReflectionTestUtils;

public class Tests
{
    // Class Under Test
    @Autowired
    private ClassUnderTest classUnderTest;

    // Mocked Class
    @MockBean
    private MockedClass mockedClass;

    @Test
    public void actualTestThatAvoidsPostConstruct()
    {
        // ============== Ignore PostConstruct Errors ==============

        // Note: You will probably want to capture the current mocked class
        // to put it back in the class under test so that other tests won't fail
        MockedClass savedMockedClass = 
        (MockedClass)ReflectionTestUtils.getField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest");

        this.mockedClass = mock(MockedClass.class);
        ReflectionTestUtils.setField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest",
            this.mockedClass);

        // ============== Setup Test ==============
        Object response = new Object();

        // Set return value when mockedClass' function is hit
        // Note: Only need to pass params if your function actually has them
        when(this.mockedClass.mockedClassFunctionBeingHit(param1, param2))
            .thenReturn(response);

        // ============== Test ==============

        this.classUnderTest.testFunction();

        // ============== Verify ==============

        // Note: Only need to pass params if your function actually has them
        verify(this.mockedClass).mockedClassFunctionBeingHit(param1, param2);

        // ============== Reset Mocked Class ==============
        ReflectionTestUtils.setField(this.classUnderTest,
            "nameOfActualBeanInClassUnderTest",
            savedMockedClass);
    }
}

根据此处的代码,您的
@计划的
代码不应在启动时运行。这个方法是在其他地方调用的吗?它是在其他地方调用的。我在触发该方法的
PostConstruct
上方添加了代码。实际上,它似乎不适合于构造后调用。可能是启动时触发的某种事件侦听器,可以放在配置文件中?我认为您最好将问题改为“单元测试时如何跳过@PostConstruct”,这不是计划问题……基于此处的代码,您的
@scheduled
代码不应该在启动时运行。这个方法是在其他地方调用的吗?它是在其他地方调用的。我在触发该方法的
PostConstruct
上方添加了代码。实际上,它似乎不适合于构造后调用。可能是启动时触发的某种事件侦听器,可以放在配置文件中?我认为您最好将问题改为“单元测试时如何跳过@PostConstruct”,这不是一个计划问题……这不会起作用。Spring将报告:“bean类与现有的、不兼容的同名bean定义冲突”,这将不起作用。Spring将报告:“bean类与现有的、不兼容的同名bean定义冲突”