为什么在 Spring 条件下不能模拟静态方法

S.L*_*Lee 6 java mockito

这是我的代码。

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;
    ...
}
Run Code Online (Sandbox Code Playgroud)

Config.isA() 的默认值为 true。我想让 Config.isA() 返回 false。所以我使用 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
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么不能mock网上的方法呢?

顺便一提。如果我测试 BCondition 类,则可以模拟 Config.isA()。我可以进入我想要的分行。它不仅仅适用于条件注释。

SKu*_*mar 2

Spring Context 在到达测试用例时已经加载。因此,经理已经选择了APolicy

如果您可以在 spring 上下文加载之前移动静态模拟配置,那么它应该符合您的期望。

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

一种方法是初始化静态模拟,如下所示 -

朱尼特4

@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
    }
}
Run Code Online (Sandbox Code Playgroud)

Junit5 请使用Jupiter的注释。

@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
}
Run Code Online (Sandbox Code Playgroud)