c# - When using TestScheduler to fire events into Observable.FromEventPattern that has an ObserveOn, the events aren't observed until next event is fired -
i seem having problem particular setup of using testscheduler observable.fromeventpattern has observeon. seems happening events both fired observe first event when sec event has fired. of course of study have done silly here , can't see doing wrong. may have missed point or trick :-)
could explain me missing in knowledge or doing wrong see 1 event, if advance 2?
i have read of info on lee campbells http://www.introtorx.com/ (which have found superb fountain of knowledge :-) )
i using:
moq v4.2.1409.1722
rx v 2.2.5.0
xunit v 1.9.2.1705
this code. own event args can watch piece of info beingness observed.
public class myeventargs : eventargs { public int info { get; private set; } public myeventargs(int data) { info = data; } }
an interface eventhandler mocked.
public interface itmp { event eventhandler<myeventargs> tmpevent; }
the class has observer , monitors events tmp object passed in, takes scheduler can test observer.
internal class someclass2 { private iobservable<eventpattern<myeventargs>> _observable; public someclass2(itmp tmp, ischeduler scheduler) { _observable = observable.fromeventpattern<myeventargs>(h => tmp.tmpevent += h, h => tmp.tmpevent -= h) .do(next => console.writeline("item came in...{0}", next.eventargs.data)) .observeon(scheduler); } public iobservable<eventpattern<myeventargs>> raw() { homecoming _observable; } }
the test.
public class tests { [fact] public void factmethodname2() { var mockedtmp = new mock<itmp>(); var testscheduler = new testscheduler(); var temp = new someclass2(mockedtmp.object, testscheduler); var count = 0; var myeventargsobserved = new list<myeventargs>(); temp.raw().subscribe( next => { count++; myeventargsobserved.add(next.eventargs); }); testscheduler.schedule(timespan.fromticks(1), () => mockedtmp.raise(tmp => tmp.tmpevent += null, new myeventargs(1))); testscheduler.schedule(timespan.fromticks(2), () => mockedtmp.raise(tmp => tmp.tmpevent += null, new myeventargs(2))); testscheduler.advanceby(1); testscheduler.advanceby(1); assert.equal(2, count); } }
console output:
item came in ...1
item came in ...2
the assert fails has observed 1 event @ point. have stepped through , have observed first event not observed until sec event has fired.
as side note test work if add together advanceby(1) or if utilize testscheduler.start instead of advanceby's, or if remove observeon , pass scheduler fromeventpattern.
this code behaving expect.
in test, schedule 2 actions on test scheduler raise events. 1 @ time t=1 , 1 @ time t=2.
then advance test scheduler time t=1. @ point, test scheduler examines it's scheduled actions see needs run. select first action raise event.
this event fired , picked observable subscriber event - subscription due observeon
operator. schedule phone call raise onnext
it's subscriber on test scheduler possible - the test scheduler not execute scheduled action until time next advanced.
this absolutely design. intention able command , observe cascade of operations , simulate reality takes amount of time rx events scheduled , executed. wouldn't want other way.
so on next timeslice, t=2, sec event raised first (it scheduled first) , onnext
phone call first event fired on subscriber observeon
. , on.
think of - every action passing through scheduler costs @ to the lowest degree 1 unit of time.
to see this, if remove observeon
line, remove intermediate scheduling , test written pass.
quite when writing reactive tests, need take business relationship of these effects , adjust assertions. reason, best practice advise scheduling actions @ to the lowest degree 1000 ticks apart. tend ticks expressions timespan.fromseconds(x).ticks
, have asserts timespan.fromseconds(x).ticks + epsilon
epsilon expected little constant.
i have used helper methods assert time within expected little range of ticks stated point - can help create tests more readable , avoid having adjust when create subtle changes.
so said, more idiomatic way write test follows:
public class tests : reactivetest { [fact] public void factmethodname2() { var mockedtmp = new mock<itmp>(); var testscheduler = new testscheduler(); var temp = new someclass2(mockedtmp.object, testscheduler); const int c = 1; var eventargs1 = new myeventargs(1); var eventargs2 = new myeventargs(2); var results = testscheduler.createobserver<myeventargs>(); temp.raw().select(ep => ep.eventargs).subscribe(results); testscheduler.schedule(timespan.fromticks(1000), () => mockedtmp.raise(tmp => tmp.tmpevent += null, eventargs1)); testscheduler.schedule(timespan.fromticks(2000), () => mockedtmp.raise(tmp => tmp.tmpevent += null, eventargs2)); testscheduler.start(); results.messages.assertequal( onnext(1000 + c, eventargs1), onnext(2000 + c, eventargs2)); } }
here derive test class reactivetest
gives onnext
helper method used in assert. using start
rather advanceby
runs test scheduler until scheduler queue empty. using test scheduler created observer (results
) lets record events , when occured easily, , assert that.
note can utilize predicate test recorded event in place of event payload more complex tests - e.g. instead of using eventargs1
in assertion args => args.data == 1
. here simplified check select
ing out event payload in subscription enable more readable equality check.
c# events system.reactive
No comments:
Post a Comment