简体   繁体   中英

Why can't mock static method in Spring condition

this is my code.

class ACondition extends SpringBootConditoin {
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (Config.isA()) {
            return new ConditionOutcome(true, "ok");
        } else {
            return new ConditionOutcome(false, "error");
        }
    }
}

class BCondition extends SpringBootConditoin {
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (Config.isA()) {
            return new ConditionOutcome(false, "error");
        } else {
            return new ConditionOutcome(true, "ok");
        }
    }
}

@Service
@Conditional(ACondition.class)
class APolicy implements Policy {
    ...
}

@Service
@Conditional(BCondition.class)
class BPolicy implements Policy {
    ...
}

class PolicyManager {
    @Autowired
    @Getter
    List<Policy> policyList;
    ...
}

the default value of Config.isA() is true. I want to make Config.isA() to return false. so I use Mockito.mockstatic.

@Autowired
PolicyManager manager;

@Test
public void get_B_policy() {
    try(MockedStatic<Config> mocked = Mockito.mockStatic(Config.class) {
        mocked.when(() -> Config.isA()).thenReturn(false);
        List<Policy> policyList = manager.getPolicyList();
        assertEquals(1, policyList.size()); // this is right
        assertTrue(policyList.get(0) instanceof BPolicy); // this is not right
    }
}

Why can't mock the online method?

by the way. If I test the BCondition class, the Config.isA() can be mocked. I can enter the branch which I want. It does not work only in conditional annotation.

Spring Context is already loaded by the time it is reaching the Test Case. Hence, Manager already has selected APolicy .

If you could move the static mock config before spring context loads, then it should match your expectations.

mocked.when(() -> Config.isA()).thenReturn(false);

One way of doing it is initialising the static Mock like below -

Junit4

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {PolicyManager.class, APolicy.class, BPolicy.class})
public class ConditionTest
{
    @Autowired
    PolicyManager manager;

    static MockedStatic<Config> mocked = Mockito.mockStatic(Config.class);

    @BeforeClass
    public static void setup()
    {
        mocked.when(() -> Config.isA()).thenReturn(false);
    }

    @AfterClass
    public static void clear()
    {
        mocked.close();
    }

    @Test
    public void get_B_policy() {
        List<Policy> policyList = manager.getPolicyList();
        assertEquals(1, policyList.size()); // this is right
        assertTrue(policyList.get(0) instanceof BPolicy); // should work now
    }
}

Junit5 Please use Jupiter's annotations.

@Autowired
PolicyManager manager;

static MockedStatic<Config> mocked = Mockito.mockStatic(Config.class);

@BeforeAll
public static void setup() { 
    mocked.when(() -> Config.isA()).thenReturn(true);
}

@AfterAll
public static void clear() {
    mocked.close();
}

@Test
public void get_B_policy() {
    List<Policy> policyList = manager.getPolicyList();
    assertEquals(1, policyList.size()); // this is right
    assertTrue(policyList.get(0) instanceof BPolicy); // should work now
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM