首页 > 解决方案 > 如何在@PostConstruct 中模拟 bean?

问题描述

我想在里面模拟一个方法调用@PostConstruct。在正常的应用程序启动期间,这会初始化数据库中的一些数据。

但是在测试或集成测试期间,我想模拟该数据库调用并返回我的模拟Set<String>

问题:@PostConstruct总是在方法中设置模拟之前调用@Before

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MockITest {
    @MockBean
    private DatabaseService db;

    @Autowird
    private MyService service; //the service to test

    @Before
    public void setup() {
        given(db.findAllByName()).willReturn(Set.of("john", "doe"));
    }

    @Test
    public void testServiceInPostConstructIsMocked() {
        service.run();
    }
}

public class MyService {
    @Autowired
    private DatabaseService db;

    private Set<String> names;

    //initialization on startup, and cache the results in the member field
    @PostConstruct
    public void init() {
        names = db.findAllByName();     
    }

    public void run() {
        System.out.println(names); //always empty for the test
    }
}

我怎样才能正确地模拟数据库服务?

标签: javaspringspring-bootjunit

解决方案


根本原因似乎@MockBean是在任何弹簧初始化和后处理完成后应用。因而也后@PostConstruct

因此,我将“名称”缓存移动到数据库服务本身,如下所示:

@Service
public class DatabaseService {
    private Set<String> names;

    public Set<String> findAllByName() {
        if (names == null) {
            names = dao.executeSql(...);
        }
        return names;
    }
}


public class MyService {
    public void run() {
        //now when this is called, the mock is already available
        System.out.println(db.findAllByName());
    }
}

也许尝试缓存内容是糟糕的代码MyService,这就是为什么 junit 和 mockito 强制以不同的方式实现?


推荐阅读