为JUnit测试提供高效的对象存储

PostgreSQL下载一个相对较大的二进制数据文件的问题。在存储和获取这些数据方面有几个限制(所有的限制都可以在官方文档中找到)。为了解决这个问题,有人建议找到更合适的数据存储。由于一些内部原因,众所周知的Amazon S3桶被选为这个目的。这个选择影响了项目的单元测试基础。仍然不可能继续使用轻量级的数据库,如HSQL或H2来实现测试。这是一个关键问题,我们将在这篇文章中尝试解决.

对象存储构建
保持集成测试活力的一个可能的解决方案是实现一些模拟的对象存储,与S3 bucket客户端完全兼容,另一方面,我们可以使用已经存在的这种类型的对象存储。MinIO是一个很好的例子,它相当简单,但高性能的对象存储,同时与Amazon S3兼容(至少在文档中是这样写的)。

为了将MinIO集成到我们的集成测试中,我们将使用一个用Java编写的强大的Testcontainers库。Testcontainers是一个特殊的库,它支持JUnit测试,并提供轻量级的、可抛弃的普通数据库、Selenium网络浏览器和其他任何可以在Docker容器中运行的实例。要开始使用这个神奇的库,只需要有Docker并在我们的pom.xml中添加以下依赖:

不幸的是,我们的目标没有合适的容器,但该库提供了所有必要的工具,可以自己轻松地创建它。幸运的是,在DockerHub上有一个MinIO的官方docker镜像。为了创建一个自己的MinIO容器,有必要用自定义数据扩展GenericContainer。DEFAULT_PORT(MonIO文档建议使用9000端口),DEFAULT_IMAGE(镜像名称),DEFAULT_TAG(镜像版本)。 要注意标签的分配! 在我们的例子中,使用了 “edge “标签来支持最后部署的MinIO版本,但在大多数情况下,最好固定标签并不时地手动更新,以避免不可预知的测试崩溃。我们也强烈建议提供凭证(访问密钥、秘密密钥)来控制对容器的访问。下面是一个实现自定义MinIO容器的例子:

public class MinioContainer extends GenericContainer {    private static final int DEFAULT_PORT = 9000;    private static final String DEFAULT_IMAGE = "minio/minio";    private static final String DEFAULT_TAG = "edge";    private static final String MINIO_ACCESS_KEY = "MINIO_ACCESS_KEY";    private static final String MINIO_SECRET_KEY = "MINIO_SECRET_KEY";    private static final String DEFAULT_STORAGE_DIRECTORY = "/data";    private static final String HEALTH_ENDPOINT = "/minio/health/ready";    public MinioContainer(CredentialsProvider credentials) {        this(DEFAULT_IMAGE + ":" + DEFAULT_TAG, credentials);    }    public MinioContainer(String image, CredentialsProvider credentials) {        super(image == null ? DEFAULT_IMAGE + ":" + DEFAULT_TAG : image);        withNetworkAliases("minio-" + Base58.randomString(6));        addExposedPort(DEFAULT_PORT);        if (credentials != null) {            withEnv(MINIO_ACCESS_KEY, credentials.getAccessKey());            withEnv(MINIO_SECRET_KEY, credentials.getSecretKey());        }        withCommand("server", DEFAULT_STORAGE_DIRECTORY);        setWaitStrategy(new HttpWaitStrategy()                .forPort(DEFAULT_PORT)                .forPath(HEALTH_ENDPOINT)                .withStartupTimeout(Duration.ofMinutes(2)));    }    public String getHostAddress() {        return getContainerIpAddress() + ":" + getMappedPort(DEFAULT_PORT);    }    public static class CredentialsProvider {        private String accessKey;        private String secretKey;        public CredentialsProvider(String accessKey, String secretKey) {            this.accessKey = accessKey;            this.secretKey = secretKey;        }        public String getAccessKey() {            return accessKey;        }        public String getSecretKey() {            return secretKey;        }    }}

测试
由于我们有一个合适的测试容器,可以作为Amazon S3桶对象存储的提供者,现在是时候用它来展示一个简单的JUnit测试的例子。当然,首先我们需要配置S3客户端来与我们的容器进行交互。在我们的案例中,我们使用原始的AmazonS3Client。因此,为了实现我们的单元测试,我们需要添加一个额外的依赖:

这里是一个普通的测试,用于创建一个具有指定名称的S3桶:

public class MinioContainerTest {    private static final String ACCESS_KEY = "accessKey";    private static final String SECRET_KEY = "secretKey";    private static final String BUCKET = "bucket";    private AmazonS3Client client = null;    @After    public void shutDown() {        if (client != null) {            client.shutdown();            client = null;        }    }    @Test    public void testCreateBucket() {        try (MinioContainer container = new MinioContainer(                new MinioContainer.CredentialsProvider(ACCESS_KEY, SECRET_KEY))) {            container.start();            client = getClient(container);            Bucket bucket = client.createBucket(BUCKET);            assertNotNull(bucket);            assertEquals(BUCKET, bucket.getName());            List buckets = client.listBuckets();            assertNotNull(buckets);            assertEquals(1, buckets.size());            assertTrue(buckets.stream()                    .map(Bucket::getName)                    .collect(Collectors.toList())                    .contains(BUCKET));        }    }    private AmazonS3Client getClient(MinioContainer container) {        S3ClientOptions clientOptions = S3ClientOptions                .builder()                .setPathStyleAccess(true)                .build();        client = new AmazonS3Client(new AWSStaticCredentialsProvider(                new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY)));        client.setEndpoint("http://" + container.getHostAddress());        client.setS3ClientOptions(clientOptions);        return client;    }}
以上仅适用于基于Junit的集成测试场景,自动化部署Mino用于集成测试依赖。单元测试场景我们更多推荐是隔离外部依赖。

今天先到这儿,希望对云原生,技术领导力, 企业管理,系统架构设计与评估,团队管理, 项目管理, 产品管管,团队建设 有参考作用 , 您可能感兴趣的文章:

如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:

Original: https://www.cnblogs.com/wintersun/p/16630888.html
Author: PetterLiu
Title: 为JUnit测试提供高效的对象存储

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/565674/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球