Testing the results of executeBlocking - unit-testing

I have a vertx handler code where I do an executeBlocking but for it to work I need to put in a Thread.sleep() in order for the code in the blocking code to fully execute to the point that I can check the results.
Is there a better way around this so I don't do a Thread.sleep?
My handler code the following is the portion where I only kept the relevant components.
try (final VertxHttpResponse response = new VertxHttpResponse(context)) {
context.vertx().executeBlocking(
future -> {
...
try {
dispatcher.invokePropagateNotFound(request,
response);
future.complete();
} finally {
...
}
}, false,
res -> {
if (res.failed()) {
context.fail(wae);
} else {
if (!context.response().ended()) {
context.response().end();
}
}
});
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
}
My test and the relevant parts
#Test
public void test(final TestContext testContext) throws Exception {
final Router router = Router.router(rule.vertx());
final SpringJaxRsHandler handler = SpringJaxRsHandler.registerToRouter(router, MyApp.class);
final RoutingContext routingContext = mock(RoutingContext.class);
when(routingContext.currentRoute()).thenReturn(router.get("/api/hello"));
when(routingContext.vertx()).thenReturn(rule.vertx());
final HttpServerRequest serverRequest = mock(HttpServerRequest.class);
when(serverRequest.absoluteURI()).thenReturn("/api/hello");
when(serverRequest.isEnded()).thenReturn(true);
when(serverRequest.method()).thenReturn(HttpMethod.GET);
when(routingContext.request()).thenReturn(serverRequest);
final HttpServerResponse response = mock(HttpServerResponse.class);
when(response.putHeader(anyString(), anyString())).thenReturn(response);
when(response.headers()).thenReturn(new VertxHttpHeaders());
when(routingContext.response()).thenReturn(response);
handler.handle(routingContext);
Thread.sleep(1000);
// fails without the sleep above
verify(response, times(1)).setStatusCode(200);
}
I tried
testContext.assertTrue(routingContext.response().ended());
But that returned false.

I refactored the code a bit so I don't use routingContext directly but the concept is still the same. I use Async in combination of a when->then(Answer) and have the async.complete() be called in the Answer. Once that is done do an async.await() to wait for the thread to finish.
final Async async = testContext.async();
when(response.write(Matchers.any(Buffer.class))).then(invocation -> {
try {
return response;
} finally {
async.complete();
}
});
when(serverRequest.response()).thenReturn(response);
router.accept(serverRequest);
async.await();

Related

s3 DeleteObjectsAsync does not work, it stops

Hi I am using this DeleteObjectsAsync and it doesn't work in a way that it looks like it stops, and it doesn't execute the next line and nothing is deleted.
I added try catch but it isn't going to any of the catches. But if I use the non-async one DeleteObjects, it works but I had to put a .Wait() like this client.DeleteObjects(deleteObjectRequest).Wait() otherwise it stops also like the DeleteObjectsAsync. It stops in a way that the RUN is still on but it just flickers after calling the delete and will not execute the next lines of codes as if it already reached the last line of it. How to make this work? thanks
My code
public static async Task<bool> DeleteFilesFromS3Async(List<KeyVersion> keyVersions, string bucketName = "")
{
try
{
using (var client = new AmazonS3Client(AmazonKey, AmazonSecretKey, AmazonRegion))
{
var deleteObjectRequest = new DeleteObjectsRequest { BucketName = bucketName , Objects = keyVersions };
await client.DeleteObjectsAsync(deleteObjectRequest);
return true;
}
}
catch (DeleteObjectsException e)
{
return false;
}
catch (AmazonS3Exception e)
{
return false;
}
catch (Exception x)
{
return false;
}
}
Make sure you are calling it the right way.
Either, caller method must be async and you must be using await there.
public async Task DeleteFile()
{
var result = await DeleteFilesFromS3Async(...);
}
Or, invoke this method synchronously.
public void DeleteFile()
{
var result = DeleteFilesFromS3Async(...).Result;
}

Testing Dart class that runs code on Isolate

I have a Dart class that performs computations on Isolate. Here is my code:
class Mapper {
SendPort _isolateSendPort;
Isolate _isolate;
Mapper() {
_asyncInit();
}
void _asyncInit() async {
final receivePort = ReceivePort();
_isolate = await Isolate.spawn(
_mappingFunction,
receivePort.sendPort,
);
_isolateSendPort = await receivePort.first;
}
static void _mappingFunction(SendPort callerSendPort) {
final newIsolateReceivePort = ReceivePort();
callerSendPort.send(newIsolateReceivePort.sendPort);
newIsolateReceivePort.listen((dynamic message) {
final crossIsolatesMessage =
message as CrossIsolatesMessage<Input>;
// some computations...
crossIsolatesMessage.sender.send(output);
});
}
Future<Output> map(Input input) async {
final port = ReceivePort();
_isolateSendPort.send(CrossIsolatesMessage<Input>(
sender: port.sendPort,
message: input,
));
return port.map((event) => event as Output).first;
}
void dispose() {
_isolate?.kill(priority: Isolate.immediate);
_isolate = null;
}
}
class CrossIsolatesMessage<T> {
final SendPort sender;
final T message;
CrossIsolatesMessage({
#required this.sender,
this.message,
});
}
This code works well when I run Flutter app. But unit test for public method Future<Output> map(Input input) throws an error NoSuchMethodError which meens _isolateSendPort is null.
Here is the unit test code:
test('Mapper map', () {
final sut = Mapper();
final inputDummy = Input('123');
final resultFuture = sut.map(inputDummy);
final expectedResult = Output('321');
expectLater(resultFuture, completion(expectedResult));
});
Here is an error:
NoSuchMethodError: The method 'send' was called on null.
Receiver: null
Tried calling: send(Instance of 'CrossIsolatesMessage<Input>')
dart:core Object.noSuchMethod
Why this error occurs in tests? And what is the right way to write tests for this class?
Problem solved.
Create of _isolate and _isolateSendPort is an async operation. Thats why _isolateSendPort was null on tests. Call method _asyncInit() from Mapper constructor is wrong way to create an isolate.
Here is working solution with lazy isolate initialization:
class Mapper {
SendPort _isolateSendPort;
Isolate _isolate;
void _initIsolate() async {
final receivePort = ReceivePort();
_isolate = await Isolate.spawn(
_mappingFunction,
receivePort.sendPort,
);
_isolateSendPort = await receivePort.first;
}
...
Future<Output> map(Input input) async {
final port = ReceivePort();
if (_isolateSendPort == null) {
await _initIsolate();
}
_isolateSendPort.send(CrossIsolatesMessage<Input>(
sender: port.sendPort,
message: input,
));
return port.map((event) => event as Output).first;
}
...
}

How can I test / mock Hive (Flutter) open box logic in repo?

Sorry if this seems a dumb question. I'm learning clean architecture as dictated by Rob Martin, and I've having a tiny bit of trouble writing one of my tests.
I wrote a couple functions in a Hive repo. Here's the code
import 'package:hive/hive.dart';
import 'package:movie_browser/features/SearchMovie/domain/entities/movie_detailed_entity.dart';
abstract class HiveMovieSearchRepoAbstract {
Future<void> cacheMovieDetails(MovieDetailed movie);
Future<MovieDetailed> getCachedMovieDetails(String id);
}
// const vars to prevent misspellings
const String MOVIEDETAILSBOX = "MovieDetailedBox";
const String SEARCHBOX = "SearchBox";
class HiveMovieSearchRepo implements HiveMovieSearchRepoAbstract {
Box movieDetailsBox = Hive.box(MOVIEDETAILSBOX) ?? null;
// TODO implement searchbox
// final searchBox = Hive.box(SEARCHBOX);
Future<void> cacheMovieDetails(MovieDetailed movie) async {
/// expects a MovieDetailed to cache. Will cache that movie
movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);
movieDetailsBox.put('${movie.id}', movie);
}
Future<MovieDetailed> getCachedMovieDetails(String id) async {
/// expects a string id as input
/// returns the MovieDetailed if cached previously
/// returns null otherwise
movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);
return await movieDetailsBox.get('$id');
}
_openBox(Box box, String type) async {
await Hive.openBox(type);
return Hive.box(type);
}
}
I can't think of how to test this? I want two cases, one where the box is already opened, and one case where it isn't.
Specifically, it's these lines I want to test
movieDetailsBox ?? await _openBox(movieDetailsBox, MOVIEDETAILSBOX);
_openBox(Box box, String type) async {
await Hive.openBox(type);
return Hive.box(type);
}
I thought about mocking the Box object then doing something like....
when(mockHiveMovieSearchRepo.getCachedMovieDetails(some_id)).thenAnswer((_) async => object)
but wouldn't that bypass the code I want tested and always show as positive?
Thanks so much for the help
i don't know if i fully understand your question but you can try something like this
abstract class HiveMovieSearchRepoAbstract {
Future<void> cacheMovieDetails(MovieDetailed movie);
Future<MovieDetailed> getCachedMovieDetails(String id);
}
// const vars to prevent misspellings
const String MOVIEDETAILSBOX = "MovieDetailedBox";
const String SEARCHBOX = "SearchBox";
class HiveMovieSearchRepo implements HiveMovieSearchRepoAbstract {
final HiveInterface hive;
HiveMovieSearchRepo({#required this.hive});
#override
Future<void> cacheMovieDetails(MovieDetailed cacheMovieDetails) async {
/// expects a MovieDetailed to cache. Will cache that movie
try {
final moviedetailbox = await _openBox(MOVIEDETAILSBOX);
moviedetailbox.put('${movie.id}', movie);
} catch (e) {
throw CacheException();
}
}
Future<MovieDetailed> getCachedMovieDetails(String id) async {
/// expects a string id as input
/// returns the MovieDetailed if cached previously
/// returns null otherwise
try {
final moviedetailbox = await _openBox(MOVIEDETAILSBOX);
if (moviedetailbox.containsKey(boxkeyname)) {
return await movieDetailsBox.get('$id');
}
return null;
} catch (e) {
return CacheException();
}
}
Future<Box> _openBox(String type) async {
try {
final box = await hive.openBox(type);
return box;
} catch (e) {
throw CacheException();
}
}
}
And to test it you can do something like this
class MockHiveInterface extends Mock implements HiveInterface {}
class MockHiveBox extends Mock implements Box {}
void main() {
MockHiveInterface mockHiveInterface;
MockHiveBox mockHiveBox;
HiveMovieSearchRepo hiveMovieSearchRepo;
setUp(() {
mockHiveInterface = MockHiveInterface();
mockHiveBox = MockHiveBox();
hiveMovieSearchRepo = HiveMovieSearchRepo(hive: mockHiveInterface);
});
group('cacheMoviedetails', () {
test(
'should cache the movie details',
() async{
//arrange
when(mockHiveInterface.openBox(any)).thenAnswer((_) async => mockHiveBox);
//act
await hiveMovieSearchRepo.cacheMovieDetails(tcacheMovieDetails);
//assert
verify(mockHiveBox.put('${movie.id}', tmovie));
verify(mockHiveInterface.openBox("MovieDetailedBox"));
});
});
group('getLocalCitiesAndCountriesAtPage', () {
test('should when', () async {
//arrange
when(mockHiveInterface.openBox(any))
.thenAnswer((realInvocation) async => mockHiveBox);
when(mockHiveBox.get('$id'))
.thenAnswer((realInvocation) async => tmoviedetails);
//act
final result =
await hiveMovieSearchRepo.getCachedMovieDetails(tId);
//assert
verify(mockHiveInterface.openBox(any));
verify(mockHiveBox.get('page${tpage.toString()}'));
expect(result, tmoviedetails);
});
});
}
You should add some tests also for the CacheExeption().
Hope this help you.
So, I wrote this post 9 months. Stackoverflow just sent me a notification saying it's a popular question, so I'll answer it for anyone else wondering the same thing
Easy way to make this testable is change Box to an arg passed into the class, like so
abstract class ClassName {
final Box movieDetailsBox;
final Box searchBox;
ClassName({
this.moveDetailsBox,
this.searchBox,
});
}
this makes the boxes mockable and testable
You should mock the hive interface and box;

Kotlin Mockk test for suspend cancellable coroutine cancellation

I have classes
// final class from some library like okhttp
class NetworkCaller {
fun call() {
// performs some real operation
}
fun cancel() {
// .... cancels the request
}
}
class Request {
suspend fun asyncRequest(): String = suspendCancellableCoroutine { continuation ->
val call = NetworkCaller()
continuation.invokeOnCancellation {
call.cancel() // i need to write a test to mock if call.cancel is getting called or not
}
// rest of the code...
}
}
When i am doing
#Test
fun testRequestCancellation() {
val request = Request()
val job = GlobalScope.launch {
val response = request.asyncRequest()
println(response)
}
runBlocking {
job.cancel()
job.join()
}
}
The job is getting cancelled and continuation.invokeOnCancellation() is getting called, i checked with println statements. But i want to mock if the call.cancel method is getting called or not, using mockk library.
I am stuck on this, need help.
In your class, expose the NetworkCaller so it can be switched out for a mock during testing:
class Request(val call: NetworkCaller = NetworkCaller()) {
suspend fun asyncRequest(): String = suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
call.cancel() // i need to write a test to mock if call.cancel is getting called or not
}
// rest of the code...
}
}
Then you can use mockk in your test:
#Test
fun testRequestCancellation() {
val mockkCall = mockk<NetworkCaller> {
coEvery { cancel() } just Runs
}
val request = Request(mockkCall)
val job = GlobalScope.launch {
val response = request.asyncRequest()
println(response)
}
runBlocking {
job.cancel()
job.join()
}
coVerify { mockkCall.cancel() }
confirmVerified(mockkCall)
}

The system crashes and can not display the error message

assume the code is correct and webservice timeout occurs.
The problem :
The system crashes and can not display the error message.
How to display error message? So I can provide an alternative to user when there is an error?
1)
I add this Class in the project :
public class MyClass
{
public static async Task LogInSuccess()
{
try
{
-- calling a web service here
}
catch (System.Exception _ex)
{
_strErrorMsg = _ex.InnerException.Message;
throw new Exception("LogInSuccess() " + _strErrorMsg);
}
}
}
--- In the MainPage,
2)
private async void SetUp ()
{
-- code for doing setUp task--
CallWebSvc();
}
3)
private void CallWebSvc()
{
bool ShowError = false;
System.Exception MyException = new Exception();
try
{
-- calling a web service thru the MyClass
System.Threading.Tasks.Task _blnLogInSuccess = MyClass.LogInSuccess();
await _blnLogInSuccess;
if (_blnLogInSuccess.IsCompleted)
{
g_blnLoginStatus = _blnLogInSuccess.Result;
}
}
catch (System.Exception _ex)
{
ShowError = true;
MyException = ex;
}
if (ShowError)
{
var MyMessageBox = new Windows.UI.Popups.MessageDialog("Remote Login Error:" + MyException.Message, "Start Login" );
await MyMessageBox.ShowAsync();
}
}
I assume your CallWebSvc method is async void (as, without async you cannot perform an await) If this is the case, you need to know async void doesn't do the same treatament to exceptions as async task. they aren't catched correctly. If you change your CallWebSvc from async void to async Task, you are going to receive the exception correctly.