0

I have an application using .NET 4.0 (so no async/await available). I am writing tests for a method that uses service calls.

So for example, my test calls method A. Method A has an async service call to method B which returns a Task and we do all the processing in ContinueWith. Method A returns nothing.

The problem is that the main thread reaches the Assert call before the ContinueWith has a chance to finish so the test fails.

The way to get around this currently is doing Thread.Sleep(10) so that the ContinueWith has time to execute. This however poses plenty of issues, such as wasting time (which adds up when having hunders - thousands of tests) to tests failing on slower machines.

I would like to know if there is any way to do a sort of Thread.WaitAll() without actually having the Task objects as there's no way to get them. Changing the code is not an option so it must be done from the tests.

Note: I am aware of methods to do it if we have the Task/Thread objects, but I don't have access to them, so please do not mark it as a duplicate of those as it is not.

Vlad Schnakovszki
  • 8,434
  • 6
  • 80
  • 114
  • I would think you'd need to do the same thing here as you would with `async/await` which is to let the `Task`s bubble up. Is there a reason you cannot make `Mathod A` return the Task that results from the `ContinueWith` so that the caller can decided to wait on it? – juharr May 09 '17 at 12:40
  • 1
    Can't you have `Method A` return the `Task` from `ContinueWith`? – Euphoric May 09 '17 at 12:40
  • Also, to point out Task and async/await are two separate things. Task was part of .NET since 4.0 and can be used without async. Its just async/await makes it's use much easier. – Euphoric May 09 '17 at 12:41
  • I can't because many of those make multiple Task calls (e.g. loading some objects and then enriching them with data from various places). Furthermore, some of them return the objects that are being enriched in the background for display so can't replace that with the task. – Vlad Schnakovszki May 09 '17 at 12:42
  • how about using a timer, say, check for every 5 seconds until `Method B` returns something? – xGeo May 09 '17 at 12:43
  • 1
    I believe your test has shown to you that your implementation is flawled. If you need to wait for the task to complete in your test, then is also obvious that you could need to wait the same task in real-life occasions. Not returning a task is the wrong choice if this is your scenario. – Federico Dipuma May 09 '17 at 12:44
  • @GeomanYabes not all the methods return something so can't really do that. – Vlad Schnakovszki May 09 '17 at 12:44
  • @FedericoDipuma this is a GUI, the user wants to see the data as quick as possible even if incomplete and the data gets populated as it comes in. Implementation is fine for what we need. – Vlad Schnakovszki May 09 '17 at 12:46
  • @VladSchnakovszki, you said "***...`method B` which returns a Task...***" – xGeo May 09 '17 at 12:47
  • Just because Method A is calling multiple sub-tasks doesn't make it impossible to use .NET 4.0 library methods to compose those tasks into single one. It just won't be as pretty as with async/await. Also, you can use back-port of async/await into .NET : http://stackoverflow.com/questions/9110472/using-async-await-on-net-4 – Euphoric May 09 '17 at 12:47
  • About the UI and responsiveness. You sure you want to use Tasks and not Reactive Observables : https://github.com/Reactive-Extensions/Rx.NET ? – Euphoric May 09 '17 at 12:48
  • @Euphoric there is a planned upgrade of .NET so no point in starting to use backports. Let's ignore async/await for this question. As I said, can't really touch the code much either as it would require a lot of regression testing. – Vlad Schnakovszki May 09 '17 at 12:49
  • So you are willing to have some dirty hack instead of redesigning your solution to use proper tools? If yes, then I want nothing to do with this. – Euphoric May 09 '17 at 12:51
  • 3
    *"Implementation is fine for what we need"* - this does not seem to be true if you are having troubles even in writing a simple test. – Federico Dipuma May 09 '17 at 12:52
  • @Euphoric It's a *huge* project, redesigning is really not feasible at all. Let's focus on the question in bold above. – Vlad Schnakovszki May 09 '17 at 12:54

1 Answers1

1

I would like to know if there is any way to do a sort of Thread.WaitAll() without actually having the Task objects as there's no way to get them.

No, there is not a way to do this reliably.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810