Testing side effects in an async function that throw exception in Dart - unit-testing

I want to test an async function for its exception behavior and side effects.
abstract class Async {
int count();
Future<void> throwExceptionAfter(int sec);
}
class ImplAsync extends Async {
int _count = 0;
#override
int count() => _count;
#override
Future<void> throwExceptionAfter(int sec) async {
await Future.delayed(Duration(seconds: sec));
_count++;
throw Exception();
}
}
The test:
void main() {
Async impl;
setUp(() {
impl = ImplAsync();
});
group('throwExeptionAfter', () {
test('simple call with waiting', () async {
expect(impl.throwExceptionAfter(0), throwsException);
await Future.delayed(Duration(seconds: 1));
var count = impl.count();
expect(count, 1);
});
test('simple call', () async {
expect(impl.throwExceptionAfter(1), throwsException);
var count = impl.count();
expect(count, 1);
});
});
}
The first test 'simple call with waiting' works, but in this test i wait a certain time to make sure that the method is completed. the second test does not work because first the test of the count is checked before the method is completed.
Is there a way to wait for the expect like that:
test('simple call', () async {
await expect(impl.throwExceptionAfter(1), throwsException);
var count = impl.count();
expect(count, 1);
});
I have already tried several possibilities but could not find a solution so far. The documentation has not helped me either. Asynchronous Tests
My tests can be found here: Github
Thanks for your help.

I have found several solutions.
One solution is to pack the method into a try-catch block:
test('simple call wiht try catch', () async {
try {
await impl.throwExceptionAfter(1);
} catch (e) {
expect(e, isInstanceOf<Exception>());
}
var count = impl.count();
expect(count, 1);
});
The other solution is to put the check on in the method whenComplete:
test('simple call with whenComplete', () async {
expect(
impl.throwExceptionAfter(1).whenComplete(() {
var count = impl.count();
expect(count, 1);
}),
throwsException);
});
I hope the answer helps others.

Related

Unexpected behaviour unit test in Streams (Dart)

I'm using two libraries to make streams: the native and getX. I created two groups for tests: the native and getX with same contract from an abstract class (AnyPresenter). One of them is Stream<bool> get isLoadingStream which for the native is _state.isLoading and for getx is isLoading.
The Streams only change when run the method below:
Native:
Getx:
I'm using the same test for both, but it is not running correctly in the native test.
Expect result:
[true, false]
Native error:
This is the sample code:
import 'dart:async';
import 'package:get/get.dart';
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
class AnyState {
bool isLoading = false;
}
abstract class AnyPresenter {
Stream<bool> get isLoadingStream;
void doSomething();
}
class StreamAnyPresenter implements AnyPresenter {
final AnyLibrary anyLibrary;
var _controller = StreamController<AnyState>.broadcast();
var _anyState = AnyState();
StreamAnyPresenter(this.anyLibrary);
Stream<bool> get isLoadingStream =>
_controller.stream.map((anyState) => anyState.isLoading).distinct();
Future<void> doSomething() async {
_anyState.isLoading = true;
_controller.add(_anyState);
_anyState.isLoading = false;
_controller.add(_anyState);
}
}
class GetXPresenter implements AnyPresenter {
final AnyLibrary anyLibrary;
var isLoading = false.obs;
GetXPresenter(this.anyLibrary);
Stream<bool> get isLoadingStream => isLoading.stream.distinct();
Future<void> doSomething() async {
isLoading.value = true;
isLoading.value = false;
}
}
abstract class AnyLibrary {
Future<void> someMethod();
}
class AnyLibrarySpy extends Mock implements AnyLibrary {}
void main() {
AnyLibrarySpy anyLibrary;
setUp(() {
anyLibrary = AnyLibrarySpy();
});
group('Using native Stream', () {
StreamAnyPresenter sut;
setUp(() {
sut = StreamAnyPresenter(anyLibrary);
});
test('Should emit events on Success', () async {
expectLater(sut.isLoadingStream, emitsInOrder([true, false]));
await sut.doSomething();
});
});
group('Using getX', () {
GetXPresenter sut;
setUp(() {
sut = GetXPresenter(anyLibrary);
});
test('Should emit events on Success', () async {
expectLater(sut.isLoadingStream, emitsInOrder([true, false]));
await sut.doSomething();
});
});
}
Sorry for any mistakes. English is not my native language

Testing AWS Lambda using Jest and Sinon causing Timeout error

I am attempting to execute the following Jest test to test an AWS Lambda locally:
const sinon = require('sinon');
const AWS = require('aws-sdk');
const { handler } = require('../queue_manager.js');
let result = {
// some result
};
let sinonSandbox;
beforeEach((done) => {
sinonSandbox = sinon.createSandbox();
done();
})
afterEach((done) => {
sinonSandbox.restore()
done();
})
it('queue-manager', async () => {
sinonSandbox.stub(AWS.DynamoDB.DocumentClient.prototype, 'get').returns({
promise: function () {
return Promise.resolve(result);
}
});
const lambdaResponse = { code: 200, data: 'some mocked data' };
var callback = function() { };
var context = {}
const event = {
somedata: "data"
};
const actualValue = await handler(event, context, callback);
expect(actualValue).toEqual(result);
});
I am attempting to test processing after a DynamoDB call, however, the test fails with a: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout
I tried giving it more time but the same result so it is not that it cannot return successfully in 5 seconds, it is not returning all.
Anyone familiar with Sinon that could possibly point out my issue?
Post edited, fist edition pushed at the bottom of the answer a
Second thought
here is an example on how to test an asynchronous function with Jest
test('the data is peanut butter', done => {
function callback(data) {
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
});
then I think the missing part in your code is the done callback on the unit test function. could you try this:
it('queue-manager', async (done) => {
sinonSandbox.stub(AWS.DynamoDB.DocumentClient.prototype, 'get').returns({
promise: function () {
return Promise.resolve(result);
}
});
const lambdaResponse = { code: 200, data: 'some mocked data' };
var callback = function() { };
var context = {}
const event = {
somedata: "data"
};
const actualValue = await handler(event, context, callback);
expect(actualValue).toEqual(result);
done();
});
Another option could be to specify the number of assertions (instead of the callback done) :
// before the await handler(...)
expect.assertions(1);
Hope this help.
First lead was the dynamo db ressource hanging:
Quite often the lambda is not returning the result and then runs into timeout because the lambda function is waiting for resources ie: dynamoDB connection for instance.
You can configure the runtime to send the response immediately by setting context.callbackWaitsForEmptyEventLoop to false.
First line of the handler must be:
context.callbackWaitsForEmptyEventLoop = false

How to unit test Stream.listen() in Dart

Consider the following test code ...
main() {
StreamController controller;
setUp(() {
controller = StreamController.broadcast(sync: false);
});
tearDown(() {
controller.close();
});
test('Stream listen test', () {
var stream = controller.stream;
stream.listen((event) {
// >>>>> How can I test if this was called?? <<<<<<
});
controller.add('Here is an event!');
});
}
... what is the correct way to test that the stream.listen(...) call-back was invoked?
stream.listen(...) doesn't return a Future so traditional expectAsyncX style matchers will not work here.
Perhaps there is some way to use the StreamSubscription.asFuture() that is returned by stream.listen(...)?
You can use expectLater function to wait for async response from your Stream and compare your Stream to your emitted value using emits , like this:
test('Stream listen test', () {
var stream = controller.stream;
final String value = 'Here is an event!';
stream.listen((event) {
// >>>>> How can I test if this was called?? <<<<<<
});
expectLater(stream, emits(value));
controller.add(value);
});
UPDATE
You can try expectAsync1 around your listen method. If no value is emitted, the timeout will be fired.
stream.listen(
expectAsync1(
(event) {
expect(event, value);
},
),
);

sinon stub a method that was executed in then call of promise

describe("/test" , ()=> {
// separate class 2
class2 = {
// function that i wanna stub
hi: function () {
return "hi";
}
}
// separate class 1
class1 = {
// function that i have stubbed and tested
method1: function() {
return new Promise((resolve, reject) => {
resolve(num);
})
}
}
// method that i will execute
var parent= function (){
class1.method1().then(()=>{
class2.hi();
})
}
// the test
it("should stub hi method",()=>{
var hiTest = sinon.stub(class2, 'hi').resolves(5);
var method1Test = sinon.stub(class1 , 'method1').resolves(5);
// this start the execution of the promise with then call
parent();
// this works fine and test pass
expect(method1Test.calledOnce.should.be.true);
// this doesn't work although i executed the function
expect(hiTest.calledOnce.should.be.true);
})
})
what i wanna do is test the hi method correctly .. because when i test if the method is executed once or not
although i executed it in the then call of the promise it doesn't show that and it make the calledOnce test fail
The problem here is that you are testing the code as if it is synchronous, when it is not (as you are using Promise).
To be able to test this properly we need to be able to hook onto the promise chain that is started with parentcalling class1.method1.
We can do this by returning the promise that calling class1.method1 returns.
In terms of the test itself, we need to make sure Mocha doesnt end the test while we are waiting for the promises, so we use the done callback parameter to tell Mocha when we think the test is finished.
describe("/test", ()=> {
class2 = {
hi: function () {
return "hi";
}
}
class1 = {
method1: function() {
return new Promise((resolve, reject) => {
resolve(num);
})
}
}
var parent = function (){
return class1.method1().then(()=>{
class2.hi();
})
}
it("should stub hi method", (done)=> {
var hiTest = sinon.stub(class2, 'hi').returns(5);
var method1Test = sinon.stub(class1 , 'method1').resolves(5);
parent().then(() => {
expect(method1Test.calledOnce.should.be.true);
expect(hiTest.calledOnce.should.be.true);
done();
});
})
})

unit testing custom knockoutjs binding

How can I unit test this knockoutjs binding where I call a certain function 'myValueAccessor' when the element is swiped on my touchpad?
I am also unsure what the unit should or is able to test at all here.
It would be ok for the first time to assert wether myValueAccessor is called.
But how can I trigger/imitate or should I say mock... the swiperight event?
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
self.myValueAccessor = function () {
location.href = 'set a new url'
};
UPDATE
I have put here my unit test with mocha.js
I can outcomment the 'value()' in the binding but still the test succeeded thats odd.
Is it not correct to put this (as a test):
function (element,args) {
alert('assertion here');
}
as a 3rd parameter into the ko.test function?
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = $(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
//value();
});
});
}
};
// Subscribe the swiperight event to the jquery on function
$.fn.on = function (event, callback) {
if (event === "swiperight") {
callback();
}
};
// Subscribe the fadeOut event to the jquery fadeOut function
$.fn.fadeOut = function (speed, callback) {
callback();
};
ko.test("div", {
tap: function () {
assert.ok(true, "It should call the accessor");
}
}, function () {
});
UPDATE:
custom.bindings.js:
define(['knockout','hammer'], function (ko,Hammer) {
return function Bindings() {
ko.bindingHandlers.tap = {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
};
});
unittest.js:
how can I connect this code to knockout in my test?
UPDATE
The Bindings is injected via require.js from my bindings.js file:
describe("When swiping left or right", function () {
it("then the accessor function should be called", function () {
ko.bindingHandlers.tap = new Bindings();
Hammer.Instance.prototype.on = function (event, callback) {
if (event === "swiperight") {
callback();
}
};
$.fn.fadeOut = function (speed, callback) {
callback();
};
var accessorCalled = false;
ko.test("div", {
tap: function () {
accessorCalled = true;
}
}, function () {
assert.ok(accessorCalled, "It should call the accessor");
});
});
});
bindings.js
define(['knockout','hammer'], function (ko,Hammer) {
return function () {
return {
'init': function (element, valueAccessor) {
var value = valueAccessor();
var hammertime1 = Hammer(element).on("swiperight", function (event) {
$(element).fadeOut('fast', function () {
value();
});
});
}
};
};
});
myviewmodel.js
...
ko.bindingHandlers.tap = new Bindings();
...
You can check my binding collection for how to test
https://github.com/AndersMalmgren/Knockout.Bindings/tree/master/test
This is my function that all my tests using
ko.test = function (tag, binding, test) {
var element = $("<" + tag + "/>");
element.appendTo("body");
ko.applyBindingsToNode(element[0], binding);
var args = {
clean: function () {
element.remove();
}
};
test(element, args);
if (!args.async) {
args.clean();
}
};
edit: Sorry forgot mocking, you just do
$.fn.on = function() {
}
I do not know what exact logic you want to test in that code since there hardly is any, but something like this
http://jsfiddle.net/Akqur/
edit:
May you get confused where i hook up your binding? Its done here
{
tap: function() {
ok(true, "It should call the accessor");
}
}
I tell ko to hook up a "tap" binding and instead of hooking in up to a observable I use a mocking function, when your custom bindnig calls value() from the fadeout function the test assert will fire
edit:
Maybe this approuch makes more sense to you?
http://jsfiddle.net/Akqur/5/
Note that it only works if your code is executed synchronous
edit:
Here i use the third argument of ko.test
http://jsfiddle.net/Akqur/8/