I am writing some testcases using RabbitMq library provided by
io.scalac.amqp
The testcase is to test consume message scenario, the code for which is something like and runs fine.
Source<Object, NotUsed> src = Source.fromPublisher(conn.consume(props.getQueue(), 1, false)).map(msg -> {
//some transformation to `ByteString` from "`Delivery`" msg
}
conn above is io.scalac.amqp.impl.RabbitConnection passed as io.scalac.amqp.impl.Connection
Parent class io.scalac.amqp.impl.Connection returns Publisher<Delivery>
while io.scalac.amqp.impl.RabbitConnection returns QueuePublisher
I write the testcase using PowerMock and spy Source class and mock like this
Source<Delivery,NotUsed> del;//Creating this object before calling the test
PowerMockito.spy(Source.class);
PowerMockito.when(Source.fromPublisher(Mockito.isA(Publisher.class))).thenReturn(del);
//Also tried
//PowerMockito.when(Source.fromPublisher(Mockito.isA(QueuePublisher.class))).thenReturn(del);
Is there any way I can test the consuming code through mocks?
Related
I am testing a service which heavily relies on project reactor.
For many tests I am mocking the return value of the component responsible for API calls.
The tests are split over multiple files.
When I run the tests of one file, they are green, but when I execute all of the test files at once, some tests fail, with the error message indicating that the mocking did not succeed (Either the injected component returned null, or the implementation of the actual component is invoked).
In the logs, there is no information about the mocking failing.
A code example:
interface API {
Flux<Bird> getBirds();
}
#Component
class BirdWatcher {
API api;
BirdWatcher(API api) {
this.api = api;
}
Flux<Bird> getUncommonBirds() {
return api.getBirds() // Although this is mocked in the test, in some runs it returns `null` or calls the implementation of the actual component
.filter(Bird::isUncommon);
}
}
#SpringBootTest
class BirdWatcherTests {
#Autowired
BirdWatcher birdWatcher;
#MockBean
API api;
#Test
void findsUncommonBirds() {
// Assemble
Bird birdCommon = new Bird("Sparrow", "common");
Bird birdUncommon = new Bird("Parrot", "uncommon");
Mockito.when(api.getBirds()).thenReturn(Flux.just(birdCommon, birdUncommon));
// Act
Flux<Bird> uncommonBirds = birdWatcher.getUncommonBirds();
// Assert
assertThat(uncommonBirds.collectList().block().size(), equalTo(1));
}
}
For me the issue seems like a race condition, but I don't know where and how this might happen, and how I can check and fix this.
I am using spring-boot-test:2.7.8, pulling in org.mockito:mockito-core:4.5.1 org.mockito:mockito-junit-jupiter:4.5.1, and org.junit.jupiter:junit-jupiter:5.8.2, with gradle 7.8.
For reactor, spring-boot-starter-webflux:2.7.8, depending on reactor:2.7.8.
I need to write an application startup event listener, here I have an #EventListener:
#EventListener
public void onApplicationEvent(ApplicationStartedEvent startedEvent)
How do I go with this? What I have done until now is, wrote many other unit tests but don't understand if I should (somehow) create an object for the ApplicationStartedEvent which doesn't sound right.
Other questions on SO like this one provide information about creating tests for custom events but this isn't a custom event and I don't want to create this object manually.
I solved it differently as I wanted to unit-test this, but seems like we can only write an Integration Test for this.
Used the following to create sample data:
private static final EasyRandomParameters EASY_RANDOM_PARAMETERS = new EasyRandomParameters()
.seed(123L)
.objectPoolSize(100)
.randomizationDepth(3)
.charset(StandardCharsets.UTF_8)
.timeRange(LocalTime.of(9, 0), LocalTime.of(17, 0))
.stringLengthRange(5, 50)
.collectionSizeRange(1, 10)
.scanClasspathForConcreteTypes(true)
.overrideDefaultInitialization(false)
.ignoreRandomizationErrors(true);
public static <T> T create(Class<T> ofType) {
EasyRandom easyRandom = new EasyRandom(EASY_RANDOM_PARAMETERS);
return easyRandom.nextObject(ofType);
}
And used it like:
ApplicationStartedEvent applicationStartedEvent = create(ApplicationStartedEvent.class);
Then called the required method. Not exactly the event listener of course but did the job.
I have unit test in spring boot written using junit and mockito . I have method that has uses method which take code block as input and perform required function . Below is sample example of code.
class A{
execute(Codeblock codeblock){
}
}
Class B {
C testFunction(){
return A.execute(()->{
code to execult ...;
});
}
}
class TestB{
#InjectMock
B b;
#Mock
A a;
void testFunction(){
when(A.execult(any())).return(C);
AssertNotNull(b.testFunction());
}
}
This code is running fine but code coverage is very low because code block is not execute. Is there any way to execute code block and increase coverage.
Testing your class (B) using mocks (A) is correct, the goal is to test any logic in B and verify the interactions with the collaborators (in this case A).
I would then create test for A (mocking Codeblock class), applying the same principle as above.
Finally I would test Codeblock logic independently.
I have gone through many documentations for getting a sample of unit testing service and controller in a Cordapp, not the flows (that is already done using in corda docs). Can anyone please help me to get an example cordapp which implemented service unit testing?
Try taking a look at the CordaService Autopayroll sample on github.
link: https://github.com/corda/samples-java/tree/master/Features/cordaservice-autopayroll
There's an ability to access registered services that gets used here in the testing code
//Test #1 check if the requestState is being sent to the bank operator behind the scene.
#Test
fun `dummy test`() {
val future = a.startFlow(RequestFlowInitiator("500", b.info.legalIdentities.first()))
network.runNetwork()
val ptx = future.get()
println("Signed transaction hash: ${ptx.id}")
listOf(a, bank).map {
it.services.validatedTransactions.getTransaction(ptx.id)
}.forEach {
val txHash = (it as SignedTransaction).id
println("$txHash == ${ptx.id}")
assertEquals(ptx.id, txHash)
}
}
link: https://github.com/corda/samples-kotlin/blob/master/Features/cordaService-autopayroll/workflows-kotlin/src/test/kotlin/net/corda/examples/autopayroll/FlowTests.kt
Good luck!
We can use Mockito module for mocking and stabbing that is required for unit testing service functions and APIs.
This link will direct more on how to mock CordaRPCops using mockito as an example.
I'm trying to use the Topology Test Driver which requires the topology in its constructor.
However, while the application itself works fine it fails in my KStream unit tests with the following error:
"StateStore ... is already added"
Here's my KStream that I'd like to test (shortened):
#Bean
public KStream<...,...> kstream(StreamsBuilder builder) {
builder.addStateStore(...);
KStream<...,...> stream = builder.stream().filter(...).etc()
stream.process(()->...);
return stream;
}
My test (shortened)
def "..."() {
given:
...
StreamsBuilder builder = new StreamsBuilder();
MyStreamService myStreamService = new MyStreamService(...stubbed);
KStream mykStream = myStreamService.kStream(builder);
TopologyTestDriver driver = new TopologyTestDriver(builder.build(), ...)
...
As soon as I run builder.build() to get the Topology it throws the above error - however I don't understand why as I'm only calling addStateStore once in that very place. I removed the entire stream logic except for the .addStoreStore() method to see if any of the other methods would initialize it (map, filter, process etc.) to no avail.
I understand there are other ways to test Kafka streams but I'm specifically trying to get it working the above explained way. If this is not possible that's okay.
In the application.yml file try to add the following line:
spring:kafka:streams:state-dir: "dir-path"
kstreams will use the "dir-path" directory for state-stores.