模拟和单元测试具有静态构建器的方法的最佳方法

时间:2017-10-16 06:18:59

标签: unit-testing amazon-s3 aws-sdk

我有以下需要测试的私有函数(针对此问题进行了简化):

private AmazonS3 getAmazonS3Client(boolean supportsEncryption) {

    AmazonS3 amazonS3;

    if (supportsEncryption) {
        amazonS3 = AmazonS3EncryptionClientBuilder
                .standard()
                .withRegion(...)
                .withCredentials(...))
                .withEncryptionMaterials(...)
                .build();
    } else {
        amazonS3 = AmazonS3ClientBuilder
                .standard()
                .withRegion(...)
                .withCredentials(...)
                .build();
    }

    return amazonS3;
}

我从另一个公共函数调用此函数,其中传递了supportsEncryption的值。

如何模拟这些静态构建器方法,以便我可以测试此分支代码是否正常工作? 或者,组织此代码以便更容易测试的好方法是什么?

1 个答案:

答案 0 :(得分:2)

封装可以模拟的抽象背后的静态实现问题。

public interface AmazonS3ClientBuilderService  {
    AmazonS3 buildClient();
    AmazonS3 buildEncryptedClient();
}

此接口的实现将包装静态构建器方法

public class DefaultAmazonS3ClientBuilderService implements AmazonS3ClientBuilderService {
    public AmazonS3 buildClient() {
        return AmazonS3ClientBuilder
            .standard()
            .withRegion(...)
            .withCredentials(...)
            .build();
    }
    public AmazonS3 buildEncryptedClient() {
        return AmazonS3EncryptionClientBuilder
            .standard()
            .withRegion(...)
            .withCredentials(...))
            .withEncryptionMaterials(...)
            .build();
    }
}

重构目标代码,而不是结构

private AmazonS3ClientBuilderService clientBuilder; // To be populated via injection.
private AmazonS3 getAmazonS3Client(boolean supportsEncryption) {
    AmazonS3 amazonS3;
    if (supportsEncryption) {
        amazonS3 = clientBuilder.buildEncryptedClient();
    } else {
        amazonS3 = clientBuilder.buildClient();
    }
    return amazonS3;
}

目标类应该通过构造函数注入遵循显式依赖原则。这将允许在通过自定义实现或模拟框架进行单独测试时替换抽象。