UnfinishedStubbingException от обновления теста - PullRequest
0 голосов
/ 04 июня 2019

У меня есть класс, и я хотел бы протестировать метод invokeEllaAsync из класса.

@Service
public class EllaService {

    private static final String SHOP_ID_STRING_SEPARATOR = ",";

    public static final int IRIS_ACCEPT = 0;
    public static final int IRIS_REJECT = 100;

    @Autowired
    @Qualifier( ELLA_CONNECTOR_BEAN_NAME )
    private EntityServiceConnectable<EllaResponseDto> connector;

    @Autowired
    @Getter
    private EllaFilterConfigHolder configHolder;

    @Autowired
    @Getter
    private EllaConfiguration config;

    @Autowired
    private Environment env;

    /**
     * Initialize the component.
     */
    @PostConstruct
    public void initialize() {
        createCustomFilters();
    }

    // ========================================================================

    /**
     * Asynchronously call Ella. Determine if traffic is applicable for Ella and if yes forward to Ella.
     *
     * @param irisBo
     * @return List<ResultBo>
     * @throws EllaGatewayUnsuccessfulResponseException
     */
    @Async
    public void invokeEllaAsync( final IrisBo irisBo ) throws EllaGatewayUnsuccessfulResponseException {

        if( !isTrafficIgnored( irisBo ) ) {

            try {
                callEllaService( irisBo );
            }
            catch( EllaGatewayUnsuccessfulResponseException ex ) {
                throw new EllaGatewayUnsuccessfulResponseException( ex.getMessage(), ex.getCause() );
            }

        }
    }

    // ========================================================================

    private boolean isTrafficIgnored( IrisBo irisBo ) {

        if( config.isExternalCostumerFilter( this.env ) && irisBo.getBuyer().isExternalKnownCustomer() ) {
            return true;
        }

        if( config.isInternalCostumerFilter( this.env ) && irisBo.getBuyer().isInternalKnownCustomer() ) {
            return true;
        }

        return checkIfShopIdFilterIsApplied( irisBo );

    }

    // ========================================================================

    private boolean checkIfShopIdFilterIsApplied( IrisBo irisBo ) {
        return configHolder.getShopIdsToFilterSet().contains( irisBo.getOrder().getShopId() );

    }

    // ========================================================================

    private void callEllaService( final IrisBo irisBo ) throws EllaGatewayUnsuccessfulResponseException {
        HttpHeaders elladHeaders = createRequestHeaders( irisBo );

        ServiceResponse<EllaResponseDto> response = connector.call( EllaDtoConverter.convertToRequest( irisBo ), elladHeaders );

        if( !response.isSuccess() ) {
            throw new EllaGatewayUnsuccessfulResponseException( response.getErrorMessage(), response.getException().getCause() );
        }
    }

    // ========================================================================

    private void createCustomFilters() {
        configHolder.setExternalCustomerFilterEnabled( config.isExternalCostumerFilter( env ) );
        configHolder.setInternalCustomerFilterEnabled( config.isInternalCostumerFilter( env ) );
        configHolder.setShopIdsToFilterSet( new HashSet<>( getShopIdsToFilterAsList( config ) ) );
    }

    // ========================================================================

    private List<Integer> getShopIdsToFilterAsList( EllaConfiguration config ) {
        String shopIdListStr = config.extractShopIdsToFilter( this.env );

        return Arrays.asList( shopIdListStr.split( SHOP_ID_STRING_SEPARATOR ) ).stream().map( s -> Integer.parseInt( s ) )
                .collect( Collectors.toList() );
    }

    // ========================================================================

    private HttpHeaders createRequestHeaders( final IrisBo irisBo ) {

        HttpHeaders ellaHeaders = new HttpHeaders();

        ellaHeaders.add( ACCEPT, APPLICATION_JSON_UTF8_VALUE );
        RatepayHeaders.append( ellaHeaders, irisBo.getRequestInfo() );

        return ellaHeaders;
    }

}

Обеспечен тестовый класс,

@RunWith( PowerMockRunner.class )
@PrepareForTest( EllaDtoConverter.class )
public class EllaServiceTest {

    private static final String VALID_TRX_ID = "valid-trx-id";
    private static final String VALID_GW_ID = "valid-gw-id";

    @InjectMocks
    private EllaService ellaService;

    private IrisBo validIrisBo;

    @Mock
    private EllaRequestDto ellaRequestDto;

    @Mock
    private EntityServiceConnectable<EllaResponseDto> entityServiceConnector;

    @Mock
    private EllaResponseDto ellaResponseDto;

    @Mock
    private EllaConfiguration mockConfig;

    @Mock
    private EllaFilterConfigHolder ellaFilterConfigHolder;

    @Mock
    private EllaService ellaServiceMock;

    @SuppressWarnings( "unchecked" )
    @Before
    public void setup() {

        PowerMockito.mockStatic( EllaDtoConverter.class );
        when( EllaDtoConverter.convertToRequest( any() ) ).thenReturn( ellaRequestDto );

        ServiceResponse<EllaResponseDto> validServiceResponseMock = mock( ServiceResponse.class );
        when( entityServiceConnector.call( any(), (HttpHeaders) any() ) ).thenReturn( validServiceResponseMock );

        when( validServiceResponseMock.isSuccess() ).thenReturn( true );
        when( validServiceResponseMock.getResponse() ).thenReturn( ellaResponseDto );
        when( validServiceResponseMock.getErrorMessage() ).thenReturn( "" );

        when( ellaServiceMock.getConfigHolder() ).thenReturn( ellaFilterConfigHolder );
        when( ellaServiceMock.getConfig() ).thenReturn( mockConfig );
        when( mockConfig.isExternalCostumerFilter( any() ) ).thenReturn( false );
        when( mockConfig.isInternalCostumerFilter( any() ) ).thenReturn( false );
        when( mockConfig.extractShopIdsToFilter( any() ) ).thenReturn( "" );

        when( ellaFilterConfigHolder.getShopIdsToFilterSet() ).thenReturn( new HashSet<>() );

        validIrisBo = new IrisBo();

        RequestInformation requestInfo = Mockito.mock( RequestInformation.class );

        when( requestInfo.getTransactionId() ).thenReturn( VALID_TRX_ID );
        when( requestInfo.getGatewayRequestId() ).thenReturn( VALID_GW_ID );

        OrderBo orderBo = new OrderBo();

        orderBo.addProduct( INVOICE );
        orderBo.setShopId( 123 );

        AddressBo addressBo = new AddressBo();

        addressBo.setStreetName( "Rutherfordstraße" );
        addressBo.setHouseNumber( "2" );
        addressBo.setZipCode( "12489" );

        ServiceBo serviceBo = new ServiceBo();

        serviceBo.setDate( LocalDate.parse( "2018-11-26" ) );
        serviceBo.setExistingCustomer( Boolean.TRUE );

        TransactionBo transactionBo = new TransactionBo();

        transactionBo.setTrxId( "valid-trx-id" );
        transactionBo.setCurrencyCode( "EUR" );
        transactionBo.setAmount( 12.5 );

        BuyerBo buyerBo = new BuyerBo();

        buyerBo.setBillingAddress( addressBo );
        buyerBo.setDeliveryAddress( addressBo );

        validIrisBo.setRequestInfo( requestInfo );
        validIrisBo.setOrder( orderBo );
        validIrisBo.setBuyer( buyerBo );

        validIrisBo.getBuyer().setBillingAddress( addressBo );
        validIrisBo.getBuyer().setDeliveryAddress( addressBo );

        validIrisBo.setTrackingId( "9241999998422820706039" );
        validIrisBo.setEmail( "test@ratepay.com" );
        validIrisBo.setIp( "123.120.12.12" );
        validIrisBo.setFirstName( "Max" );
        validIrisBo.setLastName( "Musterman" );
    }



     // some code 
}

ранее, if( !isTrafficIgnored( irisBo ) ) в упомянутом методе нет, и я тестировал как метод EllaService::invokeEllaAsync,

@Test
        public void testInvokeEllaAsyncSuccessfullyCallsCallEllaService() {

            ellaService.invokeEllaAsync( validIrisBo );

            PowerMockito.verifyStatic( EllaDtoConverter.class, VerificationModeFactory.times( 1 ) );
            EllaDtoConverter.convertToRequest( validIrisBo );

            verify( entityServiceConnector, times( 1 ) ).call( any(), (HttpHeaders) any() );
        }

После добавления условия if( !isTrafficIgnored( irisBo ) ) необходимо обновить тест. Я хотел бы реализовать, как если бы isTrafficIgnored return false, мы не будем двигаться дальше в методе. Моя реализация,

@Test
    public void testInvokeEllaAsyncSuccessfullyCallsCallEllaServiceWhenTrafficIsIgnored() throws Exception {

        ellaService.invokeEllaAsync( validIrisBo );

        EllaService e = PowerMockito.spy( ellaService );
        doReturn(false).when(e, "isTrafficIgnored", validIrisBo);

        PowerMockito.verifyStatic( EllaDtoConverter.class, VerificationModeFactory.times( 0 ) );
    }

Однако после запуска теста я получаю стек ошибок, приведенный ниже,

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.ratepay.iris.ella.service.EllaServiceTest.testInvokeEllaAsyncSuccessfullyCallsCallEllaService2(EllaServiceTest.java:173)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed


    at com.ratepay.iris.ella.service.EllaService.isTrafficIgnored(EllaService.java:105)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1846)
    at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:810)
    at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:675)
    at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
    at com.ratepay.iris.ella.service.EllaServiceTest.testInvokeEllaAsyncSuccessfullyCallsCallEllaService2(EllaServiceTest.java:173)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Я нахожусь в экосистеме Spring, если нужно упомянуть. Как правильно выполнить тест?

...