I agree with @rainerhahnekamp who said that what you are trying to achieve is more like a system/integration test.
However if you still want to do your test this way, I think it's still doable.
First, one important things to know :
Importing both fooApp
and barApp
project inside test
project will make configuration files of both projects available to the classloader, and will produce impredictable results. Exemple : only one of the two application.properties
file will be loaded. So you will have to use 2 differents profiles to load 2 separated configuration files setup.
For the same reason of projects files overlapping, beans defined by one application in packages visible by the other one will be loaded in both apps context.
To test the concept I created one service and one rest controller in each project, each with a 'profiled' property file :
barApp
@EnableAutoConfiguration(
exclude = {SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class})
@SpringBootApplication
public class BarApp {
public static void main(String[] args) {
SpringApplication.run(BarApp.class, args);
}
}
@Service
public class BarService {
public String yield() {
return "BarService !";
}
}
@RestController
public class BarResource {
private final BarService barService;
public BarResource(BarService barService) {
this.barService = barService;
}
@GetMapping("/bar")
public String getBar() {
return barService.yield();
}
}
application-bar.properties :
server.port=8181
fooApp
@EnableConfigurationProperties
@SpringBootApplication
public class FooApp {
public static void main(String[] args) {
SpringApplication.run(FooApp.class, args);
}
}
@Service
public class FooService {
public String yield() {
return "FooService !";
}
}
@RestController
public class FooResource {
private final FooService fooService;
public FooResource(FooService fooService) {
this.fooService = fooService;
}
@GetMapping("/foo")
public String getFoo() {
return fooService.yield();
}
}
application-foo.properties :
server.port=8282
test
class TestApps {
@Test
void TestApps() {
// starting and customizing BarApp
{
SpringApplication barApp = new SpringApplication(BarApp.class);
barApp.setAdditionalProfiles("bar"); // to load 'application-bar.properties'
GenericWebApplicationContext barAppContext = (GenericWebApplicationContext) barApp.run();
BarService barServiceMock = Mockito.mock(BarService.class);
Mockito.doReturn("mockified bar !").when(barServiceMock).yield();
barAppContext.removeBeanDefinition("barService");
barAppContext.registerBean("barService", BarService.class, () -> barServiceMock);
}
// starting and customizing FooApp
{
SpringApplication fooApp = new SpringApplication(FooApp.class);
fooApp.setAdditionalProfiles("foo"); // to load 'application-foo.properties'
GenericWebApplicationContext fooAppContext = (GenericWebApplicationContext) fooApp.run();
FooService fooServiceMock = Mockito.mock(FooService.class);
Mockito.doReturn("mockified foo !").when(fooServiceMock).yield();
fooAppContext.removeBeanDefinition("fooService");
fooAppContext.registerBean("fooService", FooService.class, () -> fooServiceMock);
}
RestTemplate restTemplate = new RestTemplate();
String barResourceUrl = "http://localhost:8181/bar";
ResponseEntity<String> barResponse = restTemplate.getForEntity(barResourceUrl, String.class);
String fooResourceUrl = "http://localhost:8282/foo";
ResponseEntity<String> fooResponse = restTemplate.getForEntity(fooResourceUrl, String.class);
System.out.println(barResponse.getBody());
System.out.println(fooResponse.getBody());
}
}
Launching the test produces :
mockified bar !
mockified foo !
By the way I doubt your projects will be as simple as my example and I suspect you will run into issues related to important things I highlighted earlier.