猿问

我需要模拟函数,但它不起作用,如何在不修改 src 代码的情况下构建单元测试?

这是我要测试的功能:


@Component

public class DataSourceAttributes {


    ...

    ...


    public AWSSecretDB getAttribsBySecret() throws Exception {

        AbstractConnector abstractConnector = new AWSSecretManagerConnector("secretsmanager." + region + ".amazonaws.com", region);

        GenericManager genericManager = new GenericManager(abstractConnector);

        System.out.println("Generic Manager: " + genericManager);


        AWSSecretDB awsSecretDB;

        try {

            awsSecretDB = genericManager.getSecretModel(secretName, AWSSecretDB.class);

            System.out.println("awsSecretDB: " + awsSecretDB.getEngine()); // It must be mocked

        } catch (Exception e) {

            LOGGER.error(e.getMessage(), e);

            throw e;

        }

        return awsSecretDB;

    }

}

这是我当前的单元测试:


public class DataSourceAttributesTest {


    @InjectMocks

    private DataSourceAttributes dataSourceAttributes;


    @Mock

    private GenericManager genericManagerMock;


    @Test

    public void AWSSecretDBGetAttribsBySecret() throws Exception {


        AWSSecretDB awsSecretDB = new AWSSecretDB();

        awsSecretDB.setEngine("Engine Test");

        awsSecretDB.setDbname("DB Test");

        awsSecretDB.setHost("Host Test");


        when(genericManagerMock.getSecretModel(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(awsSecretDB);

        dataSourceAttributes.getAttribsBySecret();


        // The assert is missing, but it's not important for this question

    }

}

我需要模拟genericManager来控制getSecretModel()函数,但它不起作用。


当我运行我的测试时,System.out.println(位于 getAttribsBySecret 中)打印出以下消息,证明模拟不起作用:


Generic Manager: co.com.bancolombia.commons.secretsmanager.manager.GenericManager@1349883

我知道如果我使用以下代码,模拟效果很好,但我不想重新编码它已经在 src 目录中工作的东西:

当我运行测试时,System.out.println(位于 getAttribsBySecret 中)打印:


GENERIC MANAGER: genericManagerMock

awsSecretDB: Engine Test

它如何显示,模拟效果很好。所以,这是我的问题:如何在类中使用模拟并避免在主代码中声明新属性和构造函数。我问这个是因为第一个代码有效,我不想编辑它,我认为这不是单元测试的精髓。


阿晨1998
浏览 176回答 2
2回答

动漫人物

要使用单元测试,您首先需要使代码可测试。这可能需要一些代码更改。无法在方法内部模拟局部变量,因此您需要将这些变量作为参数传递给方法,或者在对象内部创建属性并将模拟对象传递给构造函数。@Componentpublic class DataSourceAttributes {  private AbstractConnector abstractConnector;  private GenericManager genericManager;  @Autowired // to ask Spring to inject dependencies  public DataSourceAttributes(AbstractConnector abstractConnector, GenericManager genericManager) {    this.abstractConnector = abstractConnector;    this.genericManager = genericManager;  }  public AWSSecretDB getAttribsBySecret() throws Exception {    System.out.println("Generic Manager: " + genericManager);    AWSSecretDB awsSecretDB;    try {        awsSecretDB = genericManager.getSecretModel(secretName, AWSSecretDB.class);        System.out.println("awsSecretDB: " + awsSecretDB.getEngine()); // It must be mocked    } catch (Exception e) {        LOGGER.error(e.getMessage(), e);        throw e;    }    return awsSecretDB; }}然后在测试中创建对象的实例,将模拟依赖项传递给构造函数

慕盖茨4494581

如果您知道代码有效,那么首先为什么要对其进行单元测试?或者,如果您不打算更改源来修复它,为什么要执行可能带来错误的活动?但是,更严重的是,您似乎陷入了“遗留代码困境”:要修改代码,您宁愿进行适当的测试。要进行测试,您必须修改代码。对此的逃避是从刚好足以创建您需要的那些测试的微创更改开始。由于这是一种迁移方法,有时甚至可以接受一些肮脏的技巧来克服困境。Michael Feathers 在“有效处理遗留代码”中详细讨论了这一点,并提供了许多实用建议。在像 Java 这样具有自省功能的语言中,有时自省可以成为一个解决方案,以实现更好的可测试解决方案。然而,这属于肮脏的伎俩,除了作为迁移到更好解决方案的一种方式之外,我认为这是不可取的。
随时随地看视频慕课网APP

相关分类

Java
我要回答