Unit testing ViewModel property bound to ReactiveCommand IsExecuting - c#

I'm new to ReactiveUI and am following the example set out here, and unit testing as I go.
As expected, the sample code works perfectly, but my unit test which asserts that the SpinnerVisibility property changes as expected when the IsExecuting property of my ReactiveCommand changes, does not.
As per the sample, I have properties on my view model for a spinner visibility and a command to execute a search:
public Visibility SpinnerVisibility => _spinnerVisibility.Value;
public ReactiveCommand<string, List<FlickrPhoto>> ExecuteSearch { get; protected set; }
And in the view model constructor I set up the ExecuteSearch command and SpinnerVisibility is set to change when the command is executing:
public AppViewModel(IGetPhotos photosProvider)
{
ExecuteSearch = ReactiveCommand.CreateFromTask<string, List<FlickrPhoto>>(photosProvider.FromFlickr);
this.WhenAnyValue(search => search.SearchTerm)
.Throttle(TimeSpan.FromMilliseconds(800), RxApp.MainThreadScheduler)
.Select(searchTerm => searchTerm?.Trim())
.DistinctUntilChanged()
.Where(searchTerm => !string.IsNullOrWhiteSpace(searchTerm))
.InvokeCommand(ExecuteSearch);
_spinnerVisibility = ExecuteSearch.IsExecuting
.Select(state => state ? Visibility.Visible : Visibility.Collapsed)
.ToProperty(this, model => model.SpinnerVisibility, Visibility.Hidden);
}
My initial attempt was to directly invoke the command:
[Test]
public void SpinnerVisibility_ShouldChangeWhenCommandIsExecuting()
{
var photosProvider = A.Fake<IGetPhotos>();
var fixture = new AppViewModel(photosProvider);
fixture.ExecuteSearch.Execute().Subscribe(_ =>
{
fixture.SpinnerVisibility.Should().Be(Visibility.Visible);
});
fixture.SpinnerVisibility.Should().Be(Visibility.Collapsed);
}
This did result in the state => state ? Visibility.Visible : Visibility.Collapsed lambda being executed, but the subsequent assertion fails as for some reason SpinnerVisibility is still Collapsed.
My next attempt was to indirectly invoke the command by emulating a search using TestScheduler:
[Test]
public void SpinnerVisibility_ShouldChangeWhenCommandIsExecuting()
{
new TestScheduler().With(scheduler =>
{
var photosProvider = A.Fake<IGetPhotos>();
var fixture = new AppViewModel(photosProvider);
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(
() => new List<FlickrPhoto> { new FlickrPhoto { Description = "a thing", Title = "Thing", Url = "https://thing.com" } });
fixture.SearchTerm = "foo";
scheduler.AdvanceByMs(801); // search is throttled by 800ms
fixture.SpinnerVisibility.Should().Be(Visibility.Visible);
});
}
As before, the lambda executes, state is true but then instantly re-executes, with state back to false, presumably because, being mocked, photosProvider.FromFlickr would return instantly (unlike retrieving images from the API normally), which would then mean the command was no longer executing.
I then came across Paul Bett's response to a similar question, and added an Observable.Interval to my mock:
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(
() =>
{
Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler);
return new List<FlickrPhoto> {new FlickrPhoto {Description = "a thing", Title = "Thing", Url = "https://thing.com"}};
});
and the corresponding test changes:
scheduler.AdvanceByMs(501);
fixture.SpinnerVisibility.Should().Be(Visibility.Collapsed);
This had no effect.
Finally, I awaited the Interval:
A.CallTo(() => photosProvider.FromFlickr(A<string>.Ignored)).ReturnsLazily(async
() =>
{
await Observable.Interval(TimeSpan.FromMilliseconds(500), scheduler);
return new List<FlickrPhoto> {new FlickrPhoto {Description = "a thing", Title = "Thing", Url = "https://thing.com"}};
});
This allowed the fixture.SpinnerVisibility.Should().Be(Visibility.Visible) assertion to pass, but now regardless how far I advance the scheduler, the mocked method never seems to return and so the subsequent assertion fails.
Is this approach using TestScheduler correct/advised? If so, what am I missing? If not, how should this type of behaviour be tested?

First off, you are trying to test two independent things in one test. Separating the logic into more focused tests will cause you fewer headaches in the future when refactoring. Consider the following instead:
SearchTerm_InvokesExecuteSearchAfterThrottle
SpinnerVisibility_VisibleWhenExecuteSearchIsExecuting
Now you have unit tests that are verifying each piece of functionality individually. If one fails, you'll know exactly which expectation is broken because there is only one. Now, onto the actual tests...
Based on your code, I assume you're using NUnit, FakeItEasy, and Microsoft.Reactive.Testing. The recommended strategy for testing observables is to use the TestScheduler and assert the final outcome of the observable.
Here is how I would implement them:
using FakeItEasy;
using Microsoft.Reactive.Testing;
using NUnit.Framework;
using ReactiveUI;
using ReactiveUI.Testing;
using System;
using System.Reactive.Concurrency;
...
public sealed class AppViewModelTest : ReactiveTest
{
[Test]
public void SearchTerm_InvokesExecuteSearchAfterThrottle()
{
new TestScheduler().With(scheduler =>
{
var sut = new AppViewModel(A.Dummy<IGetPhotos>());
scheduler.Schedule(() => sut.SearchTerm = "A");
scheduler.Schedule(TimeSpan.FromTicks(200), () => sut.SearchTerm += "B");
scheduler.Schedule(TimeSpan.FromTicks(300), () => sut.SearchTerm += "C");
scheduler.Schedule(TimeSpan.FromTicks(400), () => sut.SearchTerm += "D");
var results = scheduler.Start(
() => sut.ExecuteSearch.IsExecuting,
0, 100, TimeSpan.FromMilliseconds(800).Ticks + 402);
results.Messages.AssertEqual(
OnNext(100, false),
OnNext(TimeSpan.FromMilliseconds(800).Ticks + 401, true)
);
});
}
[Test]
public void SpinnerVisibility_VisibleWhenExecuteSearchIsExecuting()
{
new TestScheduler().With(scheduler =>
{
var sut = new AppViewModel(A.Dummy<IGetPhotos>());
scheduler.Schedule(TimeSpan.FromTicks(300),
() => sut.ExecuteSearch.Execute().Subscribe());
var results = scheduler.Start(
() => sut.WhenAnyValue(x => x.SpinnerVisibility));
results.Messages.AssertEqual(
OnNext(200, Visibility.Collapsed),
OnNext(301, Visibility.Visible),
OnNext(303, Visibility.Collapsed));
});
}
}
Notice there is no need to even fake/mock IGetPhotos because your tests aren't verifying anything based on the duration of the command. They just care about when it executes.
Some things can be difficult to wrap your head around at first, such as when a tick actually occurs, but it's very powerful once you get the hang of it. Some debate could be had about the usage of ReactiveUI in the tests (e.g. IsExecuting, WhenAnyValue), but I think it keeps things succinct. Plus, you're using ReactiveUI in your application anyway so if those things broke your test I'd consider that a good thing.

Related

Unit Testing a Service with Moq & xUnit

Sorry, this is likely a very amateur question, but I am struggling to understand how to use Moq properly. I am quite new to unit testing as a whole, but I think I'm starting to get the hang of it.
So here's my question... I have this snippet of code below which is using a TestServer in Visual Studio that I using for am Unit Testing... I'm trying to mock IGamesByPublisher so that my test is not reliant on data in the repository (or would it be better to mock GamesByPublisher?... Or do I need to do both?)
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<IGamesByPublisher, GamesByPublisher();
}).AddAuthorization("fake.account", null);
[Fact] // 200 - Response, Happy Path
public async Task GamesByPublisher_GamesByPublisherLookup_ValidRequestData_Produces200()
{
// Arrange
var server = ServerWithRepositoryService;
// Act
var response = await server.GetAsync(Uri);
// Assert
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
Here is the IGamesByPublisher
public interface IGamesByPublisher interface.
{
Task<IEnumerable<Publisher>> Execute(GamesByPublisherQueryOptions options);
}
}
I tried
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<Mock<IGamesByPublisher>, Mock<GamesByPublisher>>();
}).AddAuthorization("fake.account", null);
And then I tried
// Not exactly what I attempted, but that code is long gone...
var mock = new Mock<IGamesByPublisher >();
var foo = new GamesByPublisherQueryOptions();
mock.Setup(x => x.Execute(foo)).Returns(true);
I didn't really find great documentation on using Moq, just the quick start guide on GitHub, which I wasn't sure how to apply (probably my own level of experience at fault there...).
I am obviously missing some fundamentals on using Moq...
You were close.
public static TestServerWithRepositoryService => new TestServer(services => {
var mock = new Mock<IGamesByPublisher>();
var publishers = new List<Publisher>() {
//...populate as needed
};
mock
.Setup(_ => _.Execute(It.IsAny<GamesByPublisherQueryOptions>()))
.ReturnsAsync(() => publishers);
services.RemoveAll<IGamesByPublisher>();
services.AddScoped<IGamesByPublisher>(sp => mock.Object);
}).AddAuthorization("fake.account", null);
The above creates the mock, sets up its expected behavior to return a list of publishers any time Execute is invoked with a GamesByPublisherQueryOptions.
It then removes any registrations of the desired interface to avoid conflicts and then registers the service to return the mock any time the interface is requested to be resolved.

FakeItEasy not verifying call for Full Framework SignalR test

I have a simple hub that I am trying to write a test for with FakeItEasy and the verification of calling the client is not passing. I have the example working in a separate project that uses MOQ and XUnit.
public interface IScheduleHubClientContract
{
void UpdateToCheckedIn(string id);
}
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
var all = A.Fake<IScheduleHubClientContract>();
var id= "123456789";
hub.Clients = clients;
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
A.CallTo(() => clients.All).Returns(all);
hub.UpdateToCheckedIn(id);
}
I'm using Fixie as the Unit Test Framework and it reports:
FakeItEasy.ExpectationException:
Expected to find it once or more but no calls were made to the fake object.
The sample below works in XUnit & MOQ:
public interface IScheduleClientContract
{
void UpdateToCheckedIn(string id);
}
[Fact]
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
var all = new Mock<IScheduleClientContract>();
hub.Clients = clients.Object;
all.Setup(m=>m.UpdateToCheckedIn(It.IsAny<string>())).Verifiable();
clients.Setup(m => m.All).Returns(all.Object);
hub.UpdateToCheckedIn("id");
all.VerifyAll();
}
I'm not sure what I've missed in the conversion?
You're doing some steps in a weird (it looks to me, without seeing the innards of your classes) order, and I believe that's the problem.
I think your key problem is that you're attempting to verify that all.UpdateToCheckedIn must have happened before even calling hub.UpdateToCheckedIn. (I don't know for sure that hub.UpdateToCheckedIn calls all.UpdateToCheckedIn, but it sounds reasonable.
There's another problem, where you configure clients.Setup to return all.Object, which happens after you assert the call to all.UpdateToCheckedIn. I'm not sure whether that's necessary or not, but thought I'd mention it.
The usual ordering is
arrange the fakes (and whatever else you need)
act, but exercising the system under test (hub)
assert that expected actions were taken on the fakes (or whatever other conditions you deem necessary for success)
I would have expected to see something more like
// Arrange the fakes
var all = A.Fake<IScheduleHubClientContract>();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
A.CallTo(() => clients.All).Returns(all); // if All has a getter, this could be clients.All = all
// … and arrange the system under test
var hub = new ScheduleHub();
hub.Clients = clients;
// Act, by exercising the system under test
var id = "123456789";
hub.UpdateToCheckedIn(id);
// Assert - verify that the expected calls were made to the Fakes
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();

Unit testing many simple method that call internal methods/other tested methods, resulting in complex (yet similar) output

I've got data access layer that has two types of method GetLatestX and GetX. GetLatestX looks something like this:
public IElementType GetLatestElementType(Guid id)
{
IElementType record = null;
using (DatabaseSession session = CreateSession())
{
record = session.Connection.Get<ElementTypeRecord>(id);
}
return record;
}
That's reasonably easy to unit test.
However, GetX wraps this GetLatest in an RefCount Observable and emits new values in response to a messaging system. Testing this method is a lot more complex. I want to check the following, rather complex behavior:
You can subscribe and a it retrieves a value from the database
It starts listening for messages
Subscribing again doesn't result in a repeated database call
When the mock message system simulates a message a new database access is called and the subscriptions get the new versions. Only one additional database call is used.
Unsubscribing the second subscription doesn't result in the system stopping listening to messages.
Unsubscribing to the first subscription results in disposal of resources, and unsubscription from the messages.
So, I've got all this in a single unit test, which is hideous. However, I'm not sure how I could break it up. I could only test 1, but to test 2 I'd have to go through 1 and 2, for 3 I'd still have to go through steps 1, 2, 3 etc. So I'd just be copying the same giant test, but having Asserts in different places each time.
And the code I'm testing in this method:
public IObservable<IElement> GetElement(Guid id)
{
return CreateObservableFor(GetLatestElement(id), GetLatestElement);
}
It's a single line, half of which has been tested earlier. The other half is private:
private IObservable<T> CreateObservableFor<T>(T entity, Func<Guid, T> getLatest)
{
Guid id = (entity as ConfigurationEntity).ID;
//return subject;
return Observable.Create<T>(observer =>
{
// publish first value
observer.OnNext(entity);
// listen to internal or external update notifications from messages
Action<ConfigurationMessage> callback = (message) =>
{
// TODO, check time-stamp is after previous?
// use callback to get latest value
observer.OnNext(getLatest(id));
};
messageService.SubscribeToConfiguration(id.ToString(), callback);
// if it has been completed and stop listening to messages
return Disposable.Create(() =>
{
Console.WriteLine("Unsubscribing from topic " + id);
messageService.UnsubscribeToConfiguration(id.ToString(), callback);
});
}).Publish().RefCount();
}
But it behaves the same way for all the GetX methods.
My first thought is I should split the GetLatestX into an interface I can test separately then mock - but that seems to split the data access class into two for no good reason other than unit tests. They don't really conceptually belong as separate units in my mind. Is there another way of 'mocking' this dependency within a class? Or should I just split them up for the sake of testing?
In the same vein, testing the functionality of GetX is effectively repeatedly testing the logic of CreateObservableFor. I see why I should be testing each API method rather than what is really the internals of the API (in case something changes), but it seems so... inefficient.
How can I structure this unit test in a better way?
Example test:
[Test]
public void GetElementTypeTest()
{
// test data
var id = Guid.NewGuid();
var nameA = "TestNameA";
var nameB = "TestNameB";
// mock database
var columnNames = new[] { "ID", "Name" };
// data values A will be the first set of data returned, and after configuration update B will be returned
var dataValuesA = new List<object[]>();
dataValuesA.Add(new object[] { id, nameA });
var dataValuesB = new List<object[]>();
dataValuesB.Add(new object[] { id, nameB });
mockDbProviderFactory = new MockDbProviderFactory()
.AddDatareaderCommand(columnNames, dataValuesA)
.AddDatareaderCommand(columnNames, dataValuesB);
// test method
IEMF emf = new EMF(mockMessageService.Object, new MockHistorian(), mockDbProviderFactory.Object, "");
var resultObservable = emf.GetElementType(id);
// check subscription to config changes has not occurred and database not accessed
mockDbProviderFactory.Verify(f => f.CreateConnection(), Times.Once);
mockMessageService.Verify(ms => ms.SubscribeToConfiguration(It.IsAny<string>(), It.IsAny<Action<ConfigurationMessage>>()), Times.Never);
//subscribe to observable
int sub1Count = 0;
var subscription = resultObservable.Subscribe(result => {
sub1Count++;
// check result
Assert.AreEqual(new ElementTypeRecord(id, (sub1Count == 1 ? nameA : nameB)), result, "Result from EMF does not match data");
});
// check subscribed to config changes and subscription called
Assert.IsTrue(sub1Count == 1, "Subscription not called");
mockMessageService.Verify(ms => ms.SubscribeToConfiguration(It.IsAny<string>(), It.IsAny<Action<ConfigurationMessage>>()), Times.Once);
// check we've subscribed with our id
Assert.AreEqual(this.configCallbacks[0].Item1, id.ToString(), "Unexpected message system subscription topic");
// open a second, short term subscription and ensure that the system does not re-subscribe to updates, or read the data again
int sub2Count = 0;
resultObservable.Take(1).Subscribe(result => {
sub2Count++;
// check result (should be second data item)
Assert.AreEqual(new ElementTypeRecord(id, nameB), result, "Result from EMF does not match data");
});
// check subscribed to config changes has not changed
mockMessageService.Verify(ms => ms.SubscribeToConfiguration(It.IsAny<string>(), It.IsAny<Action<ConfigurationMessage>>()), Times.Once);
//emit a new value by simulating a configuration change message
this.configCallbacks[0].Item2(new ConfigurationMessage(DateTime.Now));
// check subscriptions called
Assert.IsTrue(sub1Count == 2, "Subscription not called");
Assert.IsTrue(sub2Count == 1, "Subscription not called");
// unsubscribe
mockMessageService.Verify(ms => ms.UnsubscribeToConfiguration(It.IsAny<string>(), It.IsAny<Action<ConfigurationMessage>>()), Times.Never);
subscription.Dispose();
// verify subscription removed
mockMessageService.Verify(ms => ms.UnsubscribeToConfiguration(It.IsAny<string>(), It.IsAny<Action<ConfigurationMessage>>()), Times.Once);
Assert.IsTrue(this.configCallbacks.Count == 0, "Unexpected message system unsubscription topic");
// validate that the connection, command and reader were used correctly
mockDbProviderFactory.Verify(f => f.CreateConnection(), Times.Exactly(2));
mockDbProviderFactory.MockConnection.Verify(c => c.Open(), Times.Exactly(2));
mockDbProviderFactory.MockConnection.Verify(c => c.Close(), Times.Exactly(2));
//first data call
mockDbProviderFactory.MockCommands[0].Verify(c => c.PublicExecuteDbDataReader(It.IsAny<CommandBehavior>()), Times.Once);
mockDbProviderFactory.MockCommands[0].MockDatareader.Verify(dr => dr.Read(), Times.Exactly(2));
//second data call
mockDbProviderFactory.MockCommands[1].Verify(c => c.PublicExecuteDbDataReader(It.IsAny<CommandBehavior>()), Times.Once);
mockDbProviderFactory.MockCommands[1].MockDatareader.Verify(dr => dr.Read(), Times.Exactly(2));
}

how to assert mock state simultaneous with thrown exception

I'm following TDD and ran into a problem where if I make one test succeed, two others fail due to an exception being thrown. Well, I want to throw the exception, but I also want to verify the other behaviors. For instance:
public class MyTests {
[Fact]
public void DoSomethingIsCalledOnceWhenCheckerIsTrue()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(true);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
sut.CheckAndDo();
checker.VerifyGet(x => x.PassesCheck, Times.Once());
doer.Verify(x => x.Do(),Times.Once());
}
[Fact]
public void DoSomethingIsNeverCalledWhenCheckerIsFalse()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(false);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
sut.CheckAndDo();
doer.Verify(x => x.Do(),Times.Never());
}
[Fact]
public void ThrowCheckDidNotPassExceptionWhenCheckDoesNotPass()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(false);
var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);
Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
}
}
What are my choices for approaching this? What, if any, would be the "preferred" choice?
Your 1st and 2nd test passes. Then when you add the 3rd test the rest of the tests fails!.
With TDD
"Avoid altering existing tests that pass. Instead, add new tests.
Change existing tests only when the user requirements change."
I also assume your SUT (System Under Test) as below
public void CheckAndDo() {
var b = _checker.PassesCheck;
if (b) {
_doer.Do();
}
throw new CheckDidNotPassException();
}
In your SUT, when you throw a new exception, obviously it has an effect on the rest of the behaviour the way you have implemented execution logic.
So the option here would be to change the existing test(s).
Give it a well named test method, and Assert both exception and the verification.
[Test]
public void CheckAndDo_WhenPassesCheckTrue_DoCalledOnlyOnceAndThrowsCheckDidNotPassException()
{
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
checker.Setup(x => x.PassesCheck).Returns(true);
var sut = new ThingThatChecksAndDoes(checker.Object, doer.Object);
Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
doer.Verify(x => x.Do(), Times.Once());
}
Few other things you need to consider:
a. TDD produces good Unit tests. Good means, readable, maintainable and trustworthy Unit Tests.
Your test method names and the calls to SUT are poorly named. I guess this is just for the demo/Stackoverflow question. But I suggest in future you provide a real world example with real names other than "Do" "Something"
Having ambiguous names does not help from the TDD point of view as you are designing your system in small based on the requirements.
b. Publish the correct code.
In your first test you passing Mock types
var checker = new Mock<IChecker>();
var doer = new Mock<IDoer>();
var sut = new ThingThatChecksAndDoes(checker, doer);
You should pass the instances i.e (checker.Object)
When I test similar methods
I do not write a test, that x.Do() is not called
I check that exception is thrown and x.Do() is not called in one test because these two Assertions are related to the same flow.

Moq verify method fails even though method will be called

I have some troubles using Moq. Following unit test throws an exception, even though the according method will be called.
[TestMethod]
public void CreateFinishTest() {
// mock methods
factoryMock.Setup(f => f.LoadPlan("TestPlanDoNotUse")).Returns(testPlan).Verifiable();
factoryMock.Setup(f => f.CreateFinish(It.IsAny<CreateFinishMessage>(), It.IsAny<string>())).Returns(testFinish.Id).Verifiable();
try {
var cfm = new CreateFinishMessage() {
ClientId = 11,
MessageId = 23456,
CustomerId = 6,
FinishName = "MyFinish",
PlanId = "TestPlanDoNotUse"
};
var cmd = sysCfg.Executor.CreateFinish(cfm); // calls LoadPlan with cfm.PlanId and CreateFinish with cfm and cfm.PlanId
sysCfg.Executor.Execute(cmd);
factoryMock.Verify(f => f.LoadPlan("TestPlanDoNotUse"), Times.Exactly(1));
factoryMock.Verify(f => f.CreateFinish(It.IsAny<CreateFinishMessage>(), It.IsAny<string>()), Times.Exactly(1));
} catch (Exception exc) {
Assert.Fail(exc.Message);
}
}
This Error occurs:
Expected invocation on the mock exactly 1 times, but was 0 times: f => f.LoadPlan("TestPlanDoNotUse")
Configured setups:
f => f.LoadPlan("TestPlanDoNotUse"), Times.Once
Performed invocations:
IFactory.LoadPlan("TestPlanDoNotUse")
Factory.CreateFinish(IndiValue.LiveMarket.IndiCore.Communication.MessagingFormat.CreateFinishMessage, "MyFinish")
I've tried several different Verify-Calls but it won't work. And the Error which occurs seems quite confusing it's says that LoadPlan("TestPlanDoNotUse") is never called, but it's listed # Performed invocations.
Problem solved:
I think i found the problem, it wasn't a Moq problem. In sysCfg.Executor.CreateFinish(cfm) a new thread was created and started. This thread wasn't finished and so factoryMock.Verify(...) failed.
I used AutoResetEvents:
// create AutoResetEvent triggers
AutoResetEvent m_testTrigger1 = new AutoResetEvent(false);
// mock methods
factoryMock.Setup(f => f.LoadPlan(It.IsAny<string>())).Returns(testPlan).Callback(() => m_testTrigger1.Set());
// do something
// wait for triggers
bool didReturn1 = m_testTrigger1.WaitOne(timeOut);
On the Verifiable not being called, it's important that the arguments in your expectation match the arguments that are being used by the production code.
Regarding the use of Thread.Sleep, avoid it wherever possible as it will only slow down the tests to meet your slowest machine. I typically introduce WaitHandles into my tests to ensure that the tests run as fast as the code.
Take a peek here on a small utility that uses WaitHandles with events.
You do not usually use Verifiable() in your setups in conjuction with the Verify(expr, times) methods. Does it work if you remove the .Verifiable() calls?
I guess this is a me-too answer, but I believe this to be a simpler solution than many of the mentioned before.
I implemented a WaitFor function which utilizes a lambda callback to evaluate a condition:
public static void WaitFor(Func<bool> action, long timeoutMillis = 10000)
{
Stopwatch elapsed = Stopwatch.StartNew();
elapsed.Start();
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while (!action())
{
if (elapsed.ElapsedMilliseconds > timeoutMillis)
{
throw new TimeoutException("Timed out waiting for condition to become true after " + elapsed.ElapsedMilliseconds + " ms");
}
Thread.Sleep(0);
}
}
and the test code looks like this:
[Test]
public void ShouldNackUnparsableInboundMessage()
{
var nackCalled = false;
_mock.Setup(m => m.BasicNack(999, false, false)).Callback(() =>
{
nackCalled = true;
});
... do whatever which invokes the call on another thread.
WaitFor(() => nackCalled);
// Test will fail with timeout if BasicNack is never called.
}

Categories

Resources