ArrayList 上的 isEmpty() 结果为 false,尽管其大小为 0

isEmpty() on an ArrayList results in false although its size is 0

在测试中,我向另一个 class 注入了一个模拟,它似乎工作正常。但是,当我检查 ArrayList 是否为空时,尽管其 length/size 为 0,但结果为 false。这怎么会发生,我该如何解决这个问题?

@Slf4j
@Configuration
@RequiredArgsConstructor
@Setter(onMethod_ = @SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
@Getter(onMethod_ = @SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
@EnableConfigurationProperties(MyProperties.class)
public class MyConfig {

    private final MyProperties myProperties;

    private final GenericApplicationContext applicationContext;

    @PostConstruct
    void init() {
        Objects.requireNonNull(myProperties, "myProperties needs not to be null.");
        if (/*myProperties.getApps().size() == 0 || */myProperties.getApps().isEmpty()) {
            log.info("bla bla bla");
        } else {
            ...
        }
    }
}

这是我的测试 class:

@ExtendWith(MockitoExtension.class)
class MyConfigTest {

    @Mock
    MyProperties myPropertiesMock;

    @InjectMocks
    MyConfig myConfig;

    ApplicationContextRunner contextRunner;

    @Test
    void should_check_for_empty_apps() {
        contextRunner = new ApplicationContextRunner()
            .withPropertyValues("foobar.apps[0].name=", "foobar.apps[0].baseUrl=", "foobar.apps[0].basePath=")
        ;

        List apps = Mockito.mock(ArrayList.class);
        when(myPropertiesMock.getApps()).thenReturn(apps);

        myConfig.init();

        contextRunner.run(context -> {
            assertThat(apps.size()).isEqualTo(0);
        });
    }
}

属性class:

@Slf4j
@Validated
@Data
@Setter(onMethod_ = @SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
@Getter(onMethod_ = @SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
@ConfigurationProperties(prefix = MyProperties.CONFIG_PREFIX)
public class MyProperties implements LoggableProperties {

    public static final String CONFIG_PREFIX = "foobar";

    @Valid
    @NestedConfigurationProperty
    private List<MyEndpoint> apps = new ArrayList<>();

    @Data
    public static class MyEndpoint {
//        @NotNull
//        @NotEmpty
        private String baseUrl = "";

        private String basePath = "";

//        @NotNull
//        @NotEmpty
        private String name = "";
    }
}

‘app’是一个模拟。您必须模拟您使用的任何方法,否则它会检索类型的默认值。

List apps = Mockito.mock(ArrayList.class);

当您模拟一个 class 时,它的所有方法体都将被完全丢弃。具有非 void return 类型的方法 return 该类型的默认值。 size() 为 0(int 的默认值),但 isEmpty()falseboolean 的默认值)。

您可以使用 spy 而不是 mock 来获取您不模拟的方法的实际实现。这也是 when(x.method()).thenReturn(y)doReturn(y).when(x).method() 之间的区别所在。前者实际上调用了该方法,但丢弃了它的结果以支持模拟的 return 值。后者根本不调用该方法(但类型不安全)。

你嘲笑数组列表是有原因的吗?我根本没看到你使用数组列表作为模拟。