c# - Awaiting a TaskCompletionSource<T> that never returns a Task -


i trying write unit test around async pub/sub system. in unit test, create taskcompletionsource<int> , assign value within subscription callback. within subscription callback, unsubscribe publications. next time publish, want verify callback never got hit.

[testmethod] [owner("johnathon sullinger")] [testcategory("domain")] [testcategory("domain - events")] public async task domainevents_subscription_stops_receiving_messages_after_unsubscribing() {     // arrange     string content = "domain test";     var completiontask = new taskcompletionsource<int>();      domainevents.subscribe<fakedomainevent>(         (domainevent, subscription) =>         {             // set completion source awaited task can fetch result.             completiontask.trysetresult(1);             subscription.unsubscribe();             return completiontask.task;         });      // act     // publish first message     domainevents.publish(new fakedomainevent(content));     await completiontask.task;      // first result     int firstresult = completiontask.task.result;      // publish second message     completiontask = new taskcompletionsource<int>();     domainevents.publish(new fakedomainevent(content));     await completiontask.task;      // second result     int secondresult = completiontask.task.result;      // assert     assert.areequal(1, firstresult, "the first result did not receive expected value subscription delegate.");     assert.areequal(default(int), secondresult, "the second result had value assigned when shouldn't have. unsubscription did not work."); } 

when this, test hangs @ second await. understand happens due task never returning. i'm not sure how work around it. know create local field assign values this:

[testmethod] [owner("johnathon sullinger")] [testcategory("domain")] [testcategory("domain - events")] public void omainevents_subscription_stops_receiving_messages_after_unsubscribing() {     // arrange     string content = "domain test";     int callbackresult = 0;      domainevents.subscribe<fakedomainevent>(         (domainevent, subscription) =>         {             // set completion source awaited task can fetch result.             callbackresult++;             subscription.unsubscribe();             return task.fromresult(callbackresult);         });      // act     // publish first message     domainevents.publish(new fakedomainevent(content));      // publish second message     domainevents.publish(new fakedomainevent(content));      // assert     assert.areequal(1, firstresult, "the callback hit more expected, or not hit @ all."); } 

this feels wrong though. assumes never perform await operation (which when subscribers) within entire stack. test isn't safe test test finish before publish totally finished. intent here callbacks asynchronous , publications non-blocking background processes.

how handle completionsource in scenario?

it's difficult test won't ever happen. best can test didn't happen within reasonable time. have library of asynchronous coordination primitives, , unit test scenario had resort hack of observing task period of time, , assuming success (see assertex.nevercompletesasync).

that's not solution, though. perhaps cleanest solution logically fake out time itself. is, if system has sufficient hooks fake time system, can write test ensuring callback never called. sounds weird, it's quite powerful. disadvantage require significant code modifications - more returning task. if you're interested, rx place start, testscheduler type.


Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -