Writing unit test to check that event was triggered - unit-testing

I am wondering what is the correct approach. First here is the test code.
describe 'Something', ->
it 'should trigger event', (done) ->
spy = sinon.spy()
instance = new Something()
instance.on("itsdone", spy)
instance.methodCall()
spy.should.have.been.calledOnce
done()
Looks pretty straightforward, but since events are usually asynchronous, this cannot work.
class Something
constructor: ->
#events = {}
on: (event, cb) ->
#events[event] = new signals.Signal() unless #events[event]?
#events[event].add cb
methodCall: ->
# Fire up `itsdone` event when everything else is done
setTimeout (=> #events['itsdone']?.dispatch()), 0
This way test will fail obviously. Then I thought about something like this...
describe 'Something', ->
it 'should be triggering even', (done) ->
instance = new Something()
instance.on("itsdone", done)
instance.methodCall()
This works correctly and when event is not triggered, test will fail after 2 seconds. However there is no verification, that it was triggered only once. Maybe I need another test for that ? Since I already know it's triggered at least once, I can use test with spy after this one probably. Although it seems too much hassle for one event.
Another "dirty" approach could be this:
describe 'Something', ->
it 'should be triggering even', (done) ->
spy = sinon.spy()
instance = new Something()
instance.on("itsdone", spy)
instance.methodCall()
setTimeout ->
spy.should.have.been.calledOnce
done()
, 0
It isn't probably really bulletproof. It would need bigger timeout probably to be sure. However that means tests will take longer to process, which is not good idea.
Do you have any other ideas how this should be solved ?

I think your third choice is the right one:
describe 'Something', ->
it 'should be triggering even', (done) ->
instance = new Something()
instance.on("itsdone", done)
instance.methodCall()
If I understand correctly, your concern is that this doesn't test that the callback is not called twice.
In general it is difficult to test that things don't happen. For example, how long are you going to wait to see if it isn't called a second time? 2 seconds? 2 hours? You really need to use your understanding of the code being tested to know what tests are needed. Unit testing shouldn't be complete black-box testing.
I wouldn't test that it isn't called twice unless I know that the underlying code might break in a way that would cause it to be called twice.

Related

Ember concurrency timeout hanging in qunit

In Ember I have a component that starts a never-ending poll to keep some data up to date. Like so:
export default Component.extend({
pollTask: task(function * () {
while(true) {
yield timeout(this.get('pollRate'));
this.fetchSomeData();
}
}).on('init')
})
This causes a preexisting acceptance test to get stuck in this task and run forever, even though it should be run asynchronously. The test looks like this:
test('my test', async function(assert) {
mockFindRecord(make('fetched-model'));
await visit('/mypage'); // gets stuck here
await typeIn('input', 'abc123');
assert.ok(somethingAboutThePage);
});
I thought at first that I had mocked the request wrong and that the test was just timing out, but it was in fact correctly polling data. Removing this task makes the acceptance test finish normally.
Testing this manually seems to work fine, and nothing gets stuck. Why is this happening and what is the right way to address this?
Saw Unit testing ember-concurrency tasks and yields but it doesn't really help since it only deals with unit tests.
You're not doing anything wrong and this is a common gotcha with ember-concurrency. Ember-concurrency's timeout() function relies on Ember.run.later() to create the timeout and fortunately or unfortunately, Ember's test suite is aware of all timers created with Ember.run.later() and will wait for all timers to settle before letting the test continue. Since your code is using an infinite loop your timers will never settle so the test hangs. There's a nice little section about testing asynchronous code in the Ember guides here.
There's a section in the ember-concurrency docs about this exact problem here. I recommend you look through it to see their recommendations on how to tackle this although it seems as if there's no real elegant solution at the time.
The quickest and probably easiest way to get this to not hang would be to throw in a check to see if the app is being tested (gross, I know):
pollTask: task(function * () {
while(true) {
yield timeout(this.get('pollRate'));
this.fetchSomeData();
if (Ember.testing) return; // stop polling to prevent tests from hanging
}
}).on('init')
You can also try to throw in a call to Ember.run.cancelTimers() in your tests/helpers/start-app.js file (another suggestion in that section):
window._breakTimerLoopsId = Ember.run.later(() => {
Ember.run.cancelTimers();
}, 500);
But it doesn't seem to appear in the API docs so I personally wouldn't rely on it.

Run function/behaviour after all behaviours ended in Pony

I have a simple Publish-Subscriber that I want to write tests for.
The methods called here are all behaviours, except get_number_consumed_messages that would be a function.
class iso _SinglePubSub is UnitTest
fun name(): String => "single publish/consume"
fun apply(h: TestHelper) =>
let p = Publisher("publisher message", h.env.out)
let queue = Queue(1, h.env.out)
let c = Consumer(h.env.out)
p.publish_message(queue)
p.publish_message(queue)
c.consume_message(queue)
c.consume_message(queue)
//Run after all behaviours are done
let n = c.get_number_consumed_messages()
h.assert_eq[USize](2, n)
How would someone implement the get_number_consumed_messages function/behaviour or how would you have to modify the test function?
First of all, c.get_number_consumed_messages() must be a behaviour as well. It is the only way to let one actor communicate with another. This has the added benefit of behaviours being run in the same order as they are called, which means c.get_number_consumed_messages() would run after both calls to c.consume_message(queue).
Given that, since Consumer is also an actor, calling it with behaviours -- and not methods -- means that we cannot return data from it directly. To actually receive data from another actor, you should use the Promise pattern, for example:
use "promises"
actor Consumer
var message_count: USize = 0
be consume_message(queue: OutStream) =>
... // Do some things
message_count = message_count + 1
... // Do other things
be get_number_consumed_messages(p: Promise[USize]) =>
p(message_count)
To actually test it, you would need to follow an adapted version of the Testing Notifier Interactions pattern for long tests, for example:
use "ponytest"
use "promises"
class iso _SinglePubSub is UnitTest
fun apply(h: TestHelper) =>
h.long_test(2_000_000_000)
... // Produce and consume messages
let p = Promise[USize]
p.next[None]({(n: USize): None =>
h.assert_eq[USize](2, n)
h.complete(true) })
c.get_number_consumed_messages(p)
(Notice the extra calls to h.long_test and h.complete, as well as the promise wrapping a lambda with the end of our test.)
For more information on these concepts, I would recommend familiarizing yourself with the stdlib documentation on Promises and the "Long tests" section of Ponytest.

Assertions in kotlin coroutines / callback

Fairly new to kotlin.
I'm testing a http client which executes the calls asynchronously and takes a callback as argument from the caller.
Now, let's assume the caller is a unit test. Asserting INSIDE the callback doesn't work obviously because it runs in some kind of background io thread (using Kluent for asserts, I really like the syntax).
client.query(identifier, uiCallback = {
System.out.println("Found a total of ${it.total} entries with identifier!")
signal.countDown()
it.total shouldBe 1
})
I could defer the assert to outside of the callback, but i think that's not very elegant.
In an android context with java i would have done something like "runOnUIThread" (before RX). I also have to use that api in android, so I'll run into that problem anyways.
I must be missing sg. very basic. Is is state of the art to use junit for kotlin anyways or is there a better way to go?
EDIT: That "signal" there is a CountdownLatch to wait for the asynchronous execution.
EDIT 2: Retrofit service definition:
#GET("Entity")
fun query(#Query("identifier") identifier: Array<String?> = arrayOfNulls(0),
#Query("_count") count:Int = 10): Call<ResponseBody>

trouble debugging async Task in unit test because it's not entered

So I am trying to test a method of type async Task that is called inside of a command handler, inside that method I have some ifs and I want to check on which branch it goes.
Because on each branch a certain method is called, I can see which branch it went to by
await myRepository.Received(1).Method1(3, null);
Imagine the key method is like this:
public async Task MyKeyMethod(int x) {
if (x == 21)
Method1("bla");
if (x == 22)
Method2("blue");
if (x == 23)
Method3("ba");
}
So I want to test that the call MyKeyMethod(2) actually goes into the branch that calls Method2("blue");
And I know that I can do this by something like:
await MyKeyMethod.Received(1).Method2(22); // Received(1) means that method was invoked once.
Question 1: what should 22 be? The parameter supplied to Method2 or the one supplied to MyKeyMethod?
Question2: Why does my code not even enter any async Task method that I have inside the command handler (during debugging)?
Is there any concrete example that you have?
I am able to enter step by step the command by doing something like:
var cmd = new MyCommand(myObject); // myObject is an object that I mocked earlier (gave it some dummy values for each field)
var commandResponse = await handler.Handle(cmd);
Assert.That(commandResponse.IsSuccessful, Is.True);
...just NOT at the next deeper level, like the async Tasks inside those commands. I can just at the moment simulate what the async Task return, which is not what I want in this instance.
Question 3. Could this be because those async Task methods are inside a repository that is mocked by using
myRepository = Substitute.For<IMyRepository>();
Question 4. How do I enter actually not mockingly Task methods found inside Repositories that are mocked?
I am still getting the hang of it, "it" being the broader subject of unit tests in NUnit, but apparently my hunch was right. Because the repository was mocked, I could not enter and debug inside of one of its contained methods. So I used a real (not fake) method of the repository which by the way took in its constructors some fake instances of other dependant repos or services, and then I could go inside that Task.
So, factually, instead of:
myRepository = Substitute.For<IMyRepository>();
I went and created a real instance, such as:
var myRepository = new MyRepository>(mockService1, mockRepo2);
where mockService1 was mocked using Substitute like previously pointed out.
And by doing so I could then debug a method like:
myRepository.MyMethod(x) which previously the debugger couldn't analyse the inside of.
If you have a better way of phrasing my conclusions, by all means, or more complete explanation, please go ahead. Thank you

Sinon stub instance method declared in mapDispatchToProps

New to testing and React Redux, so I may be conflating a few issues here. I will only present one example, but I have tried many different combinations of mount(), shallow(), instance(), stub, spy and more.
Given a component, where setFooData() updates redux state and Foo.props.data:
const mapDispatchToProps = (dispatch, props) => ({
setFooData(fooId, data) {
dispatch(Actions.setFooData(fooId, data));
},
});
...
return (
<div fooId={this.props.fooId}>
<Foo {...fooProps}/>
</div>
);
I would like to write some tests around the conditions under which setFooData() is called, namely conditions in lifecycle methods like componentDidMount() and componentWillReceiveProps().
Because setFooData() involves server calls and more, and because these tests merely concern the view layer and how the component renders as a result of Foo.props.data being set eventually by setFooData(), setFooData() seems like a good candidate for stub.
Therefore, Enzyme's shallow(), rather than mount(), seems appropriate, correct? In any case, when I try to stub setFooData():
let wrapper = return shallow(<Foo {...props}/>);
let stub = sinon.stub(wrapper.instance(), 'setFooData');
I receive the error:
Attempted to wrap undefined property setFooData as function
Upon inspection, wrapper.instance() yields an object where setFooData() is indeed not defined, but according to other examples, I would think it should be.
Furthermore, setFooData() does exist on wrapper.instance().selector.props, and while let stub = sinon.stub(wrapper.instance().selector.props, 'setFooData'); avoids the error, when I inspect the object setFooData() =/= stub, and the function is not called as per the test.
When I use mount() instead,
let wrapper = mount(<Provider store={store}><Foo {...props}/></Provider>);
let componentDidMountSpy = sinon.spy(Foo.prototype, 'componentDidMount');
let componentWillReceivePropsSpy = sinon.spy(Foo.prototype, 'componentWillReceiveProps');
expect(componentDidMountSpy.called).to.be.true; //passes
expect(componentWillReceivePropsSpy.called).to.be.true; //passes
expect(stub.called).to.be.true; //fails
I receive a different error that appears related to the body of setFooData(), so setFooData() is called but the function is not actually stubbed to prevent its real body from being executed.
Thanks for any help to clarify my understanding.
I think you're taking the hardest path. You should test your component in isolation, not the connected one. If you test the connected component you're making an integration test and double testing that connect indeed works. That's already tested in react-redux for you.
Instead, test your action creators by themselves in unit tests.
Then, export your component as named export without connecting and use the default export for the connect version.
That way you can simply import the pure-React version and pass anything you want as props, in order to make easy assertions afterwards.
If you need to specifically test that something happens in those lifecycle methods, you can call those methods from the instance:
const fakeActionCreator = sinon.spy()
const subject = mount(<MyComponent doSomething={ fakeActionCreator } />)
subject.instance().componentDidMount()
assert.equal(fakeActionCreator.callCount, 1)