unit tests vs background thread

  • Thread starter Thread starter Brad White
  • Start date Start date
B

Brad White

I am creating a backgroundworker, but I think this question
is applicable for any kind of background thread.

How do you get it to work in a unit test?

The .NET concept seems to be that everything uses Invoke
which seems to require a GUI with a windows mesage loop
to pick up on it. In Delphi/Win32, we would just call
CheckSynchronize which would pick up on the Synchronize.

But I'm not calling synchronize/invoke directly in my .NET code.
It is buried in the backgroundworker.

I have found several posts that spell out the same problem. Half
never got answered, and the other half say "Oh, never mind, I see."

Like this one:
http://www.eggheadcafe.com/software/aspnet/29191764/backgroundworker-does-not.aspx
He appears to have gotten around the exception, but he doesn't say how.
I can only assume that his solution is to give up on using the
backgroundworker. But every other solution also seems to use
Control.Invoke, so I don't see how that helps.

So, I have two problems.

One, Invoke requires a windows handle
http://msdn2.microsoft.com/en-us/library/system.windows.forms.control.invoke.aspx

Control.Invoke Method

Executes a delegate on the thread that owns the control's underlying
window handle.
If you don't have that handle, it says that you'll get an exception
which is where we are. So I need a way to simulate a handle.

Two, how to pick up the invoke from the main thread without a windows
message loop.

Or, a way to get this to work without using Control.Invoke at all.

Thanks,
Brad.
 
I'm not sure I follow the question. Your background worker needs to use
invoke if it interacts with the UI thread. There is nothing that says the
background worker needs to interact with the UI thread though. You can, for
example, use a background worker in a console app. Are you trying to update
a UI control?
 
Family Tree Mike wrote on 2/4/2008 :
I'm not sure I follow the question. Your background worker needs to use
invoke if it interacts with the UI thread. There is nothing that says the
background worker needs to interact with the UI thread though. You can, for
example, use a background worker in a console app. Are you trying to update
a UI control?

Thanks for the reply.
I can see that aspect wasn't clear.

This is a unit test. The object that is running in the background
doesn't know whether there is a UI or not and shouldn't behave any
differently if there is. If it behaved differently, then it wouldn't
be a valid test.

So at instantiation, we provide a delegate for updating the UI.
In the unit test, this is just a call back to the test itself.
The background thread doesn't need to know that. It just needs
to call invoke on the delegate to execute the delegate in the
foreground thread.
But there is no UI in the foreground thread when running in a
unit test. It is just a console app. So our test just fails
because Invoke can't find a windows handle.

If someone can tell me how to use a background worker in a console
app and invoke on the foreground thread, we should be home free.

Thanks,
Brad.
 
[...]
This is a unit test. The object that is running in the background
doesn't know whether there is a UI or not and shouldn't behave any
differently if there is. If it behaved differently, then it wouldn't
be a valid test.

Then the UI-specific behavior doesn't belong in the unit test.
So at instantiation, we provide a delegate for updating the UI.
In the unit test, this is just a call back to the test itself.
The background thread doesn't need to know that. It just needs
to call invoke on the delegate to execute the delegate in the
foreground thread.

Note: the Invoke() method of a delegate is _very_ different from the
Control.Invoke() method. You seem to be using the two ideas
interchangeably (i.e. "needs to call invoke on the delegate", or in other
words "needs to execute Delegate.Invoke()").
But there is no UI in the foreground thread when running in a
unit test. It is just a console app. So our test just fails
because Invoke can't find a windows handle.

What Invoke() are you using? Delegate.Invoke() would never need to look
for a window handle, and you shouldn't even be able to get at
Control.Invoke() if you're not in a Forms-based application.
If someone can tell me how to use a background worker in a console
app and invoke on the foreground thread, we should be home free.

There is no built-in way to do that. For a Forms-based application, the
main thread has a message pump that is constantly sitting and waiting for
something to show up in the message queue so that it can process it.
Invoking takes advantage of that by putting some custom data in the
message queue that the Control class then uses for invoking.

But there's no managed equivalent for a console application. Your main
thread does whatever it does straight through. There's no built-in
message pump loop that can be used to deliver invoke requests to an object
on the main thread.

That said, it's unusual to need to do this in a console application. The
need exists for Forms-based applications because of particular needs of
the Forms control classes themselves. But in a console application, the
issue is almost always best handled simply by allowing the code to run in
whatever thread it's already in and using normal thread synchronization
techniques to ensure that data structures remain synchronized across
threads (assuming that's necessary at all...sometimes it's not).

If you do have the very rare situation of actually needing to execute code
on a specific thread in a console application, the only practical way to
do this in a managed application is to create your own mechanism. For
example, a producer/consumer pattern where the thread that should execute
delegates is the consumer and any other thread that has delegates to be
executed on that first thread are the producers.

But I very much doubt you really need to do this.

Pete
 
Peter Duniho has brought this to us :
On Tue, 05 Feb 2008 07:14:34 -0800, Brad White

We obviously have a failure to communicate.
[...]
This is a unit test. The object that is running in the background
doesn't know whether there is a UI or not and shouldn't behave any
differently if there is. If it behaved differently, then it wouldn't
be a valid test.

Then the UI-specific behavior doesn't belong in the unit test.
We are in agreement on that.
What part of running a separate thread is UI-specific?
Note: the Invoke() method of a delegate is _very_ different from the
Control.Invoke() method. You seem to be using the two ideas interchangeably
(i.e. "needs to call invoke on the delegate", or in other words "needs to
execute Delegate.Invoke()").
Let's put it this way.
I have a bckground worker in my app. There is no UI-specific
code, beyond using the background worker. I want to unit test
this and run it as part of my suite. So it needs to run in a
console app.
I'm running into the same issue as this guy:
http://www.eggheadcafe.com/software/aspnet/29191764/backgroundworker-does-not.aspx

What Invoke() are you using? Delegate.Invoke() would never need to look for
a window handle, and you shouldn't even be able to get at Control.Invoke() if
you're not in a Forms-based application.
That's the point. How do I get the background thread to communicate
with the foreground thread without any forms?
There is no built-in way to do that. For a Forms-based application, the main
thread has a message pump that is constantly sitting and waiting for
something to show up in the message queue so that it can process it.
Invoking takes advantage of that by putting some custom data in the message
queue that the Control class then uses for invoking.
Sure.

But there's no managed equivalent for a console application. Your main
thread does whatever it does straight through. There's no built-in message
pump loop that can be used to deliver invoke requests to an object on the
main thread.
Exactly. It would have to be written. That part is not difficult
and I've done it before in other languages. What I can't find is
what exactly that loop would call.
That said, it's unusual to need to do this in a console application. The
need exists for Forms-based applications because of particular needs of the
Forms control classes themselves. But in a console application, the issue is
almost always best handled simply by allowing the code to run in whatever
thread it's already in and using normal thread synchronization techniques to
ensure that data structures remain synchronized across threads (assuming
that's necessary at all...sometimes it's not).
This is a unit test of production code. How can it not be common
to need to test this? Is no one writing threaded code?
If you do have the very rare situation of actually needing to execute code on
a specific thread in a console application, the only practical way to do this
in a managed application is to create your own mechanism. For example, a
producer/consumer pattern where the thread that should execute delegates is
the consumer and any other thread that has delegates to be executed on that
first thread are the producers.
I can't change the architecture, just for this.

Thanks for giving me the opportunity to clarify,
Brad.
 
Peter Duniho has brought this to us :
On Tue, 05 Feb 2008 07:14:34 -0800, Brad White

We obviously have a failure to communicate.
[...]
This is a unit test. The object that is running in the background
doesn't know whether there is a UI or not and shouldn't behave any
differently if there is. If it behaved differently, then it wouldn't
be a valid test.

Then the UI-specific behavior doesn't belong in the unit test.
We are in agreement on that.
What part of running a separate thread is UI-specific?

Well, for one, so far the only stated need to run this code on a separate
thread is having a GUI. Is there something about this code that otherwise
precludes simply running it on a single thread in a console application?
Let's put it this way.
I have a bckground worker in my app. There is no UI-specific
code, beyond using the background worker.

Then why are you using the BackgroundWorker?

My recollection is that it is possible to set up a synchronization context
for a thread that will allow the BackgroundWorker to operate without a
Forms-based GUI, but in a similar way to if you had one. But if I recall,
it's not all that simple to do and generally the BackgroundWorker is
specifically for cases where you have a Forms-based GUI.

If you have no Forms-based GUI, then typically it would be the case that
using a BackgroundWorker is unnecessary.
I want to unit test
this and run it as part of my suite. So it needs to run in a
console app.
I'm running into the same issue as this guy:
http://www.eggheadcafe.com/software/aspnet/29191764/backgroundworker-does-not.aspx

That guys appears to be writing a GUI application. I'm not clear on how
you're running into the same problem, given that your concern is
specifically about what happens when there's no GUI.

Beyond that, there is not generally a problem using BackgroundWorker in
non-Forms applications. If there is no synchronization context, the
BackgroundWorker will raise all of the relevant events on the same thread
used to run the DoWork event handler, rather than marshal the events to
another thread. But otherwise it works fine.

A quick look at the code you've referenced above shows that he is not
using the Forms classes correctly. In particular, he's creating a Control
instance without any containing Form, and he never enters a message pump
that would allow that Control instance to process messages sent to it. In
other words, he's lying to BackgroundWorker by claiming he's got a Control
that can be used to marshal events to a specific thread, when in fact that
Control is never available to receive events (or any window messages for
that matter).

If this is relevant to your own code, it means you are similarly misusing
the Forms classes. On the other hand, if you are not misusing the Forms
classes, then that example isn't relevant to this discussion.
That's the point. How do I get the background thread to communicate
with the foreground thread without any forms?

Short of creating a new synchronization context and pumping messages for
it, I'm not aware of any built-in way. It's not a common requirement.

It is not difficult to write your own solutions, but you should not bother
doing so unless there's a genuine need.
[...]
But there's no managed equivalent for a console application. Your main
thread does whatever it does straight through. There's no built-in
message pump loop that can be used to deliver invoke requests to an
object on the main thread.
Exactly. It would have to be written. That part is not difficult
and I've done it before in other languages. What I can't find is
what exactly that loop would call.

I'm not clear on this question. If you've implemented this before in
other languages, then you must have used mechanisms similar to those
available in .NET to do so. In .NET, you'd use those mechanisms as well.

I've already described one possible solution: a producer/consumer design
using delegates as the commodity.
This is a unit test of production code. How can it not be common
to need to test this? Is no one writing threaded code?

Lots of people write threaded code. But the only reason one would
typically need to execute code on a specific thread is in situations where
that requirement is imposed by .NET. And in those situations, .NET
provides a suitable mechanism for doing so.

Conversely, in the situations in which .NET provides no mechanism, it's
very rare to have the need, even when the code has multiple threads.
I can't change the architecture, just for this.

I doubt you need to. But you haven't offered enough details for me or
anyone else to say for sure whether doing so would be necessary or if
there's some alternative approach.

You have asserted a need to execute code on a specific thread. I have
explained that there's no convenient way to do this outside of a
Form-based GUI application (you can use a synchronization context, but I
wouldn't call that convenient).

I still question your assertion of the need stated, but assuming that's
really a need, you are stuck either implementing this yourself or using a
synchronization context to handle things. Neither approach is really all
that difficult, and IMHO wouldn't represent a huge change in architecture
(not only would it not be a lot different than using a Form-based GUI, it
should plug into the code in much the same way if done correctly). But
it's not what I'd call convenient, and like I said: I doubt you really
need to do this.

If the above doesn't give you enough information to proceed, you really
should post a concise-but-complete sample of code that demonstrates what
you're trying to do and what doesn't work. Please note: every word in
"concise-but-complete" is important. The code should be brief, the
shortest code required to demonstrate exactly the issue, without any
additional stuff in it. But it also needs to be able to be compiled and
run without any additional effort on anyone's part. And of course, in the
context of any such sample, you need to explain very clearly what parts
work as desired, what parts don't, and why.

Pete
 
Back
Top