I've been using Rx and more specifically ReactiveUI for a while in a project and have got myself into a situation where I think I need some advice.
The problem is that, given a command is executed (a button is clicked) I want to show a message box, one which the user will answer Yes or No. Depending on the answer, I then want to do some more stuff. As I'm using MVVM with unit tests I'd like the MessageBox to be testable; i.e. to be replaced by some other code. This is essentially what I've got.
In my view model:
this.ExternalObservable = this.SomeOperationCommand
.SelectMany(_ => this.UserWantsToContinueWithOperation())
.Where(x => x)
.Select(_ => this.SomeData)
.Where(x => x != null);
private IObservable<bool> UserWantsToContinueWithOperation() {
var subject = new Subject<bool>();
var box = new GuiMsgBox("Continue?",
result => {
subject.OnNext(result == System.Windows.MessageBoxResult.Yes);
});
MessageBus.Current.SendMessage(box);
return subject;
}
And the GuiMsgBox is essentially a wrapper around the System.Windows.MessageBox class which I listen to using the MessageBus in the UI and in my tests.
This all works fine when running the application, but in unit tests, as the bus is then using the Immediate scheduler, it's obviously not working the same way.
I feel there's some design glitch here, so any input on the actual problem; to show a message box, returning a result, which can be tested, would be greatly appreciated!
It's hard to tell without seeing more implementation details, but I would consider using TestScheduler instead. In RxUI.Testing, this is as easy as:
(new TestScheduler()).With(sched => {
// Write your test here, all the schedulers will be
// implicitly set to your 'sched' scheduler.
});
Here's an example of a bunch of MVVM-related tests, testing a Pomodoro timer:
https://github.com/xpaulbettsx/ReactiveUI/blob/master/ReactiveUI.Sample/ReactiveUI.Sample.Tests/ViewModels/BlockTimerViewModelTest.cs
Here's another good example of MVVM-based testing from my Rx book (sorry about the plug), specifically using CreateColdObservable in order to mock input (i.e. testing the scenario of "Click a button, wait 10 seconds, check result")
https://github.com/ProgRx/Chapter-9
Related
If we set up a Saga and immediately Publish(context => ...) then a message successfully hits the bus.
If however, we have something like
Initially(
When(SomeCommand)
.Then(context => { context.Instance.SomeField = 5 })
.TransitionTo(SomeState)
.Then(context => this.RaiseEvent(context.Instance, SomeEvent)));
During(SomeState,
When(SomeEvent)
// ConsumeContext is not available here
.Publish(context => new SomeEventClass
{
Foo = context.Instance.SomeField
})
.Finalize());
The machine also never transitions to the Final state presumably because of the exception locating a ConsumeContext.
We have seen some references to passing a ConsumeContext as a parameter in Publish() however it's unclear as to which context this needs (Intellisense just makes reference to context1, context2, context3, etc).
Is there a way to use Publish() after RaiseEvent() has already been called? If not, is there a way to publish an event using some other mechanism?
MassTransit version is 5.1.5 and Automatonymous is 4.1.2
EDIT Based on Chris Patterson's answer here we have tried adding the below outside of any Initially or During
WhenEnter(NewState, state => state.Publish(context =>
new EventClass { Foo = context.Instance.Foo }
)
.Finalize();
However it still doesn't publish anything and the state never transitions to Final. If we add a Then it also never hits this code block. There don't seem to be any exceptions occurring. We also tried using When(SomeState.Enter) and it also doesn't work.
Side question as maybe this will help with my understanding of why Publish and RaiseEvent don't seem to play nicely together - why does Publish need the ConsumeContext? Is it to locate the bus and bindings?
You should be able to add
When(SomeState.Enter)
to your Initially section, and it will use the existing context. By creating a new EventContext with RaiseEvent, you aren't retaining the ConsumeContext.
You could also add WhenEnter(SomeState) outside of any Initially or During block.
The solution to this turned out to be using this:
.Then(context => context.Raise(SomeEvent))
instead of this:
.Then(context => this.RaiseEvent(context.Instance, SomeEvent))
It kinda makes sense now - the latter (as mentioned by Chris Patterson) creates a new EventContext while the former uses the given context. We didn't know that Raise was a method available on the passed in context.
So I've been trying to write a test for mass transit using the in-memory feature. I wondered what peoples approach was to waiting for consumers to execute. In the example below a use a sleep or I've also tried a while loop, but not a fan of either, any better ideas? I basically want to check that the consumer is executed.
[Fact]
public async Task SomeTest()
{
var busControl = Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ReceiveEndpoint("commands", ec =>
{
ec.LoadFrom(context);
});
});
var address = new Uri(bus.Address, "commands")
await sendEndpoint.Send(MyExampleCommand());
Thread.Sleep(2000);
//Check nsubstitute mock received
}
Look at the test harness features that are built into MassTransit. They should give you some good ideas of how to test them.
You can look at the harness tests to see how they should be used. Note that they work with any test framework, not just NUnit.
https://github.com/MassTransit/MassTransit/blob/develop/tests/MassTransit.Tests/Testing/ConsumerTest_Specs.cs
The Testing documentation explains how to use the test harnesses.
I am having 2 issues testing MassTransit consumers:
Sync issue
MessageData
The first one is like this:
var testConsumer = TestFactory.ForConsumer<ImageUploadConsumer>().New(
test =>
{
test.UseConsumerFactory(new InstanceConsumerFactory<ImageUploadConsumer>(ImageConsumer));
test.Publish(message, (scenario, context) =>
{
});
});
testConsumer.Execute(); //Is non blocking
The following line (below) fails, because this line:
moqFileMetaRepo.Verify(_ => _.Add(It.IsAny<IFileMeta>()),Times.Once );
is executed 9.9/10 before... this line ever did:
public async Task Consume(ConsumeContext<ImageUploadWithThumb> context)
My fix has been to do
moqFileMetaRepo
.Setup(repo => repo.Add(It.IsAny<IFileMeta>()))
.Callback(() => { AutoEvent.Set(); });
And call the following before the assert:
AutoEvent.WaitOne(TimeSpan.FromSeconds(10));
Which is really a lot of work. And makes TDD or Testing in general a hassle, which I fear is only going to get ignored over time.
MessageData issue is another one. Here's the payload I'm sending through
message = new ImageUploadWithThumb()
{
Id = Guid.NewGuid(),
FileName = "Test.jpg",
User = "Me",
Extension = "jpg",
OriginalImage = new ConstantMessageData<byte[]>(new Uri("https://g00gle.com"), new byte[] { 1, 2, 3 })
};
I'm expecting to get byte[] { 1, 2, 3 } on the other end without having to resort to creating an actual persistence.
Instead:
On the sender side the MessageData.Value resolves ok. The consumer totally bombs. Works in prod though =_= which is not where testing should be.
I really just want to mock and UnitTest my consumer w/o having to wrestle with the framework - preferably in under 5 mins or so. Is there a way out while sticking to MT3?
I would suggest looking at the MassTransit.TestFramework package. It does require NUnit, but you could always take the classes and port it to your own test framework.
All of the MassTransit unit tests are written using the fixtures in this framework. The original .Testing namespace is in a world of hurt right not, it didn't survive completely and I'm unsure it's actually working completely. It wasn't designed for async, so it was difficult to transition without trashing it entirely.
I have made one WCF service Method which is consuming third party service methods(call methodA, methodB, methodC) and here all three belongs to different services i.e. serviceA, serviceB, serviceC.
Each method accepting single input object for processing (not List of input object). but I have to work on multiple objects, so I am consuming this methods in for loop.
Now the problem is, suppose I have 3 objects to process with methodA, 2 objects to process with methodB and 5 objects to process with methodC and consider each method taking 1 sec to process then total time taken to process all is almost 10 seconds. To overcome this problem after googling I got options like threading and parallel-linq. of course I don't have enough knowledge about threading and its performance, I choose to stay away. Now with parallel linq I found performance is up. But still expectations are not satisfied (and sometime its throwing timeout exception).
So please advice what should i try now? whether to dive in threading or anything other to try?
As TPL in general or Parallel class are solutions too, I suggest you to try out the TPL Dataflow library as you have a data flowing across your application, and your code will be much more structured this way.
So you can create 3 ActionBlock<> objects, each for the services you have, and post data to them in your loop. Also you can add task continuation handler for them so you'll be notified then all of messages are consumed by the services. Also you can add a BufferBlock<T> and link it to other ones with filter function. The code will be something like this:
void ProducingMethod()
{
var serviceABlock = new ActionBlock<YourInputObject>(o =>
{
serviceA.Call(o);
});
serviceABlock.Completion.ContinueWith(t =>
{
sendNotifyA();
});
var serviceBBlock = new ActionBlock<YourInputObject>(o =>
{
serviceB.Call(o);
});
serviceBBlock.Completion.ContinueWith(t =>
{
sendNotifyB();
});
var serviceCBlock = new ActionBlock<YourInputObject>(o =>
{
serviceC.Call(o);
});
serviceCBlock.Completion.ContinueWith(t =>
{
sendNotifyC();
});
foreach (var objectToProcess in queue)
{
if (SendToA)
{
serviceABlock.SendAsync(objectToProcess);
}
else if (SendToB)
{
serviceBBlock.SendAsync(objectToProcess);
}
else if (SendToC)
{
serviceCBlock.SendAsync(objectToProcess);
}
}
}
I'm currently building a class using TDD. The class is responsible for waiting for a specific window to become active, and then firing some method.
I'm using the AutoIt COM library (for more information about AutoIt look here) since the behavior I want is actually a single method in AutoIt.
The code is pretty much as the following:
public class WindowMonitor
{
private readonly IAutoItX3 _autoItLib;
public WindowMonitor(IAutoItX3 autoItLib)
{
_autoItLib = autoItLib;
}
public void Run() // indefinitely
{
while(true)
{
_autoItLib.WinWaitActive("Open File", "", 0);
// Do stuff now that the window named "Open File" is finally active.
}
}
}
As you can see the AutoIt COM library implements an interface wich I can mock (Using NUnit and Rhino Mocks):
[TestFixture]
public class When_running_the_monitor
{
WindowMonitor subject;
IAutoItX3 mockAutoItLibrary;
AutoResetEvent continueWinWaitActive;
AutoResetEvent winWaitActiveIsCalled;
[SetUp]
public void Setup()
{
// Arrange
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
mockAutoItLib.Stub(m => m.WinWaitActive("", "", 0))
.IgnoreArguments()
.Do((Func<string, string, int, int>) ((a, b, c) =>
{
winWaitActiveIsCalled.Set();
continueWinWaitActive.WaitOne();
return 1;
}));
subject = new Subject(mockAutoItLibrary)
// Act
new Thread(new ThreadStart(subject.Run)).Start();
winWaitActiveIsCalled.WaitOne();
}
// Assert
[Test]
[Timeout(1000)]
public void should_call_winWaitActive()
{
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Bestand selecteren", "", 0));
}
[Test]
[Timeout(1000)]
public void ensure_that_nothing_is_done_while_window_is_not_active_yet()
{
// When you do an "AssertWasCalled" for the actions when the window becomes active, put an equivalent "AssertWasNotCalled" here.
}
}
The problem is, the first test keeps timing out. I have already found out that when the stub "WinWaitActive" is called, it blocks (as intended, on the seperate thread), and when the "AssertWasCalled" is called after that, execution never returns.
I'm at a loss how to proceed, and I couldn't find any examples of mocking out a blocking call.
So in conclusion:
Is there a way to mock a blocking call without making the tests timeout?
(P.S. I'm less interested in changing the design (i.e. "Don't use a blocking call") since it may be possible to do that here, but I'm sure there are cases where it's a lot harder to change the design, and I'm interested in the more general solution. But if it's simply impossible to mock blocking calls, suggestions like that are more that welcome!)
Not sure if I understand the problem.
Your code is just calling a method on the mock (WinWaitActive). Of course, it can't proceed before the call returns. This is in the nature of the programming language and nothing you need to test.
So if you test that WinWaitActive gets called, your test is done. You could test if WinWaitActive gets called before anything else, but this requires ordered expectations, which requires the old style rhino mocks syntax and is usually not worth to do.
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
subject = new Subject(mockAutoItLibrary)
subject.Run()
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
You don't do anything else then calling a method ... so there isn't anything else to test.
Edit: exit the infinite loop
You could make it exit the infinite loop by throwing an exception from the mocks. This is not very nice, but it avoids having all this multi-threading stuff in the unit test.
mockAutoItLibrary = MockRepository.GenerateStub<IAutoItX3>();
// make loop throw an exception on second call
// to exit the infinite loop
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Repeat.Once();
mockAutoItLib
.Stub(m => m.WinWaitActive(
Arg<string>.Is.Anything,
Arg<string>.Is.Anything,
Arg<int>.Is.Anything));
.Throw(new StopInfiniteLoopException());
subject = new Subject(mockAutoItLibrary)
try
{
subject.Run()
}
catch(StopInfiniteLoopException)
{} // expected exception thrown by mock
mockAutoItLib.AssertWasCalled(m => m.WinWaitActive("Open File", "", 0));
Your Test only contains a call to the mocked method. Therefore it tests only your mock instead of any real code, which is an odd thing to do. We might need a bit more context to understand the problem.
Use Thread.Sleep() instead of AutoResetEvents: Since you are mocking the COM object that does the blocking window-active check, you can just wait for some time to mimick the behavior, and then make sure that the window is indeed active by making it active programmatically. How you block should not be important in the test, only that you block for some significant time.
Although from your code it is not clear how winWaitActiveIsCancelled and continueWinWaitActive contribute, I suspect they should be left out of the WinWaitActive mock. Replace them with a Thread.Sleep(500).