Home > other >  How to mock autowired object partially for one single test?
How to mock autowired object partially for one single test?

Time:07-12

I have a config class AppConfig to receive environment variables and use them inside service MyService

// application.yml
app-config:
  env-var1: ${ENV_VAR1:}
  env-var2: ${ENV_VAR2:}
  env-var3: ${ENV_VAR3:}
  env-var4: ${ENV_VAR4:}
  env-var5: ${ENV_VAR5:}

// AppConfig.java
@Data
@EnableConfigurationProperties
@ConfigurationProperties(value = "app-config")
public class AppConfig {
    private String envVar1;
    private String envVar2;
    private String envVar3;
    private String envVar4;
    private String envVar5;
}

// MyService.java
@Slf4j
@Service
public class MyService {
    @Autowired
    AppConfig appConfig;
  
    public void doSomething() {
        log.info(appConfig.getEnvVar1());
        log.info(appConfig.getEnvVar2());

        // business logic controlled by appConfig.envVar1 and appConfig.envVar2
        // other variables not used
    }
}

Now I am writing unit test for MyService

// MyServiceTest.java
@SpringBootTest
class MyServiceTest {
    @Autowired
    AppConfig appConfig;

    @Autowired
    MyService myService;

    @BeforeEach
    void setUp() {
        // reset override
    }

    @AfterEach
    void tearDown() {
        // reset override
    }

    @Test
    void doSomething_envVar1() {
        // override appConfig.envVar1 only

        myService.doSomething()
    }

    @Test
    void doSomething_envVar2() {
        // override appConfig.envVar2 only

        myService.doSomething()
    }
}

How can I override only one variable inside AppConfig in one test only (and reset it after the test)?

CodePudding user response:

I think you can use @DirtiesContext annotation. Using this annotation, you can restart spring context when every test methods end.

@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyServiceTest {
    @Autowired
    AppConfig appConfig;

    @Autowired
    MyService myService;

    
    @Test
    void doSomething_envVar1() {
        // override appConfig.envVar1 only

        myService.doSomething()
    }

    @Test
    void doSomething_envVar2() {
        // appConfig.envVar1 is not effected by envVar1() test
        // override appConfig.envVar2 only

        myService.doSomething()
    }
}

more examples are on baeldung guide: https://www.baeldung.com/spring-dirtiescontext

CodePudding user response:

You can override yaml variables for the test. You need a test profile application-test.yaml. There you can override your variables. Also annotate your test class with @ActiveProfiles("test"). Your test will use default yaml and override variables, that are declared in "test" yaml. But you'll have to isolate the test, that uses different yaml params into another test. Check out this question: Load different application.yml in SpringBoot Test

@ActiveProfiles("test")
@SpringBootTest
class SpecialMyServiceTest {

Also you can specify properties in @SpringBootTest annotation

@SpringBootTest(
    properties = { "spring.application.name=example", "ENV_VARIABLE=secret" }
)

But still, they spread on all test cases of this class

There's also a @DynamicPropertySource annotation, maybe it will help you. Check out this page - maybe you'll find suitable solution there

  • Related