admin管理员组

文章数量:1405731

I have a class where I am using transactional template and I wrote a Junit test for the same. However when I run the coverage,I do not have any line coverage on the code. The test is although green. This confuses me. Can somebody be kind enough to help me resolve this. Below is my production code.

 @Test
    void test() {
        Optional<SomeParam> someParam = Optional.empty();
        String TOPIC = "topic";
        Token token = getToken();
        Stream<Token> tokenStream = Stream.of(token);
        TokenDto tokenDto = getDto();
        when(specificDataMapper.fromToken(token)).thenReturn(tokenDto);
        doAnswer(invocation -> {
            TransactionCallbackWithoutResult callback = new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    Stream<Token> stream = tokenRepository.streamAll();
                    stream.forEach(t -> {
                        TokenDto payload = specificDataMapper.fromToken(t);
                        pubSubTemplate.publish(TOPIC, payload);
                    });
                }
            };
            callback.doInTransaction(null);
            return null;
        }).when(transactionTemplate).executeWithoutResult(any());
        doReturn(tokenStream).when(tokenRepository).streamAll();

       publisherService.publishservice(someParam);

    
    }

When I run in debug, the test is not entering the lamda function.

I have a class where I am using transactional template and I wrote a Junit test for the same. However when I run the coverage,I do not have any line coverage on the code. The test is although green. This confuses me. Can somebody be kind enough to help me resolve this. Below is my production code.

 @Test
    void test() {
        Optional<SomeParam> someParam = Optional.empty();
        String TOPIC = "topic";
        Token token = getToken();
        Stream<Token> tokenStream = Stream.of(token);
        TokenDto tokenDto = getDto();
        when(specificDataMapper.fromToken(token)).thenReturn(tokenDto);
        doAnswer(invocation -> {
            TransactionCallbackWithoutResult callback = new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    Stream<Token> stream = tokenRepository.streamAll();
                    stream.forEach(t -> {
                        TokenDto payload = specificDataMapper.fromToken(t);
                        pubSubTemplate.publish(TOPIC, payload);
                    });
                }
            };
            callback.doInTransaction(null);
            return null;
        }).when(transactionTemplate).executeWithoutResult(any());
        doReturn(tokenStream).when(tokenRepository).streamAll();

       publisherService.publishservice(someParam);

    
    }

When I run in debug, the test is not entering the lamda function.

Share edited Mar 10 at 8:24 Rohi asked Mar 7 at 11:31 RohiRohi 4272 gold badges5 silver badges18 bronze badges 3
  • 2 The best thing is, that test subject - #publishEnrollmentData - is not even included in the snippet. – Antoniossss Commented Mar 7 at 20:19
  • I can only guess, but your stubbed executeWithoutResult method never calls the real code – why do you expect that? It creates a new transaction callback and then executes this one. It completely ignores the code inside your publish method – knittl Commented Mar 9 at 15:46
  • Similar question: stackoverflow/questions/76930616/… – knittl Commented Mar 9 at 17:38
Add a comment  | 

1 Answer 1

Reset to default 1

The stubbed methods of your mock instances in your test never call your real method:

doAnswer(invocation -> {
    TransactionCallbackWithoutResult callback = new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            Stream<Token> stream = tokenRepository.streamAll();
            stream.forEach(t -> {
                TokenDto payload = specificDataMapper.fromToken(t);
                pubSubTemplate.publish(TOPIC, payload);
            });
        }
    };
    callback.doInTransaction(null);
    return null;
}).when(transactionTemplate).executeWithoutResult(any());

It simply creates a new TransactionCallbackWithoutResult instance and uses that to execute the code in the test (which seems to be copied verbatim from your production code's publishMessage method?)

You probably want to call your real method. While this is possible to do in the doAnswer block, it becomes convoluted and unmaintainable pretty quickly. Instead, I'd suggest to create a simple fake implementation of TransactionTemplate to be used in your test. A trivial implementation simply calls the callback, without performing any transaction handling:

private static class FakeTransactionTemplate extends TransactionTemplate {
  @Override
  public <T> T execute(final TransactionTemplate<T> action) throws TransactionException {
    return action.doInTransaction(new SimpleTransactionStatus());
  }
}

Remove your Mockito mock and inject an instance of the fake transaction template into your service.


If you still want to use Mockito to re-implement the logic, you need to call the real template in your stub:

doAnswer(invocation -> {
    final TransactionCallback<?> callback = invocation.getArgument(0)
    callback.doInTransaction(new SimpleTransactionStatus()); // call the real callback!
    return null;
}).when(transactionTemplate).executeWithoutResult(any());

But I'd advise against that. It gives you nothing over the fake implementation and only makes reasoning about your code harder.

本文标签: javaUnit testing using transaction templateStack Overflow