public async Task HandlesExceptionsThrownImmediatelyByInnerPublisher() { const int expectedResult = 42; var exceptionToThrow = new PublishException(); var exceptionsThrown = new List <Exception>(); var innerPublisher = Substitute.For <IResultPublisher>(); innerPublisher.Publish(Arg.Any <Result <int, int> >()) .Throws(exceptionToThrow); var fireAndForgetPublisher = new FireAndForgetResultPublisher(innerPublisher, ex => { exceptionsThrown.Add(ex); }); var mock = Substitute.For <IControlCandidate <int, string> >(); mock.Control().Returns(expectedResult); mock.Candidate().Returns(expectedResult); var scientist = new Scientist(fireAndForgetPublisher); var result = scientist.Experiment <int>("myExperiment", experiment => { experiment.Use(mock.Control); experiment.Try(mock.Candidate); }); await fireAndForgetPublisher.WhenPublished(); Assert.Equal(new List <Exception> { exceptionToThrow }, exceptionsThrown); }
public void RunsBothBranchesOfTheExperimentAndMatchesExceptionsForInstance() { var mock = Substitute.For <IControlCandidate <int> >(); mock.Control().Returns(x => { throw new InvalidOperationException(); }); mock.Candidate().Returns(x => { throw new InvalidOperationException(); }); const string experimentName = nameof(RunsBothBranchesOfTheExperimentAndMatchesExceptions); var resultPublisher = new InMemoryResultPublisher(); var scientist = new Scientist(resultPublisher); var ex = Assert.Throws <AggregateException>(() => { scientist.Experiment <int>(experimentName, experiment => { experiment.Use(mock.Control); experiment.Try("candidate", mock.Candidate); }); }); Exception baseException = ex.GetBaseException(); Assert.IsType <InvalidOperationException>(baseException); mock.Received().Control(); mock.Received().Candidate(); Assert.True(resultPublisher.Results <int>(experimentName).First().Matched); }
public void PublishOperation() { var publisher = Substitute.For <IResultPublisher>(); var ex = new Exception(); publisher.Publish(Arg.Any <Result <int, int> >()).Throws(ex); const int expectedResult = 42; var mock = Substitute.For <IControlCandidate <int> >(); mock.Control().Returns(expectedResult); mock.Candidate().Returns(0); var scientist = new Scientist(publisher); var result = scientist.Experiment <int>(nameof(PublishOperation), experiment => { experiment.Thrown(mock.Thrown); experiment.Use(mock.Control); experiment.Try(mock.Candidate); }); Assert.Equal(expectedResult, result); mock.Received().Thrown(Operation.Publish, ex); }
public async Task PublishesAsynchronously() { const int expectedResult = 42; var pendingPublishTask = new TaskCompletionSource <object>(); // Create a new publisher that will delay all // publishing to account for this test. var innerPublisher = Substitute.For <IResultPublisher>(); innerPublisher.Publish(Arg.Any <Result <int, int> >()) .Returns(call => pendingPublishTask.Task); var fireAndForgetPublisher = new FireAndForgetResultPublisher(innerPublisher, ex => { }); var mock = Substitute.For <IControlCandidate <int, string> >(); mock.Control().Returns(expectedResult); mock.Candidate().Returns(expectedResult); var scientist = new Scientist(fireAndForgetPublisher); const int count = 10; Parallel.ForEach( Enumerable.Repeat(0, count), src => { var result = scientist.Experiment <int>("myExperiment", experiment => { experiment.Use(mock.Control); experiment.Try(mock.Candidate); }); Assert.Equal(expectedResult, result); }); // Make sure that the above science calls are still publishing. Task whenPublished = fireAndForgetPublisher.WhenPublished(); Assert.NotNull(whenPublished); // Ensure that the mock was called before the when published task has completed. mock.Received(count).Control(); mock.Received(count).Candidate(); Assert.False(whenPublished.IsCompleted, "When Published Task completed early."); pendingPublishTask.SetResult(null); await whenPublished; Assert.True(whenPublished.IsCompleted, "When Published Task isn't complete."); }
public void RunsBothBranchesOfSimpleSynchronousExperimentAndReportsFailure() { const string experimentName = nameof(RunsBothBranchesOfSimpleSynchronousExperimentAndReportsFailure); var resultPublisher = new InMemoryResultPublisher(); var science = new Scientist(resultPublisher); var result = science.Experiment <int>(experimentName, experiment => { experiment.Use(() => 42); experiment.Try(() => 37); }); Assert.Equal(42, result); Assert.False(resultPublisher.Results <int>(experimentName).First().Matched); Assert.True(resultPublisher.Results <int>(experimentName).First().Mismatched); }
public void ScientistDisablesAllExperiments() { const int expectedResult = 42; var mock = Substitute.For <IControlCandidate <int> >(); mock.Control().Returns(expectedResult); mock.Candidate().Returns(0); var settings = Substitute.For <IScientistSettings>(); settings.Enabled().Returns(Task.FromResult(false)); var instanceMock = Substitute.For <IControlCandidate <int> >(); instanceMock.Control().Returns(expectedResult); instanceMock.Candidate().Returns(0); using (Swap.Enabled(settings.Enabled)) { var result = Scientist.Science <int>(nameof(ScientistDisablesExperiment), experiment => { experiment.Use(mock.Control); experiment.Try(mock.Candidate); }); mock.DidNotReceive().Candidate(); mock.Received().Control(); settings.Received().Enabled(); var scientist = new Scientist(Substitute.For <IResultPublisher>()); scientist.Experiment <int>(nameof(ScientistDisablesAllExperiments), experiment => { experiment.Use(instanceMock.Control); experiment.Try(instanceMock.Candidate); }); instanceMock.DidNotReceive().Candidate(); instanceMock.Received().Control(); settings.Received().Enabled(); } }
public async Task HandlesDelayedExceptionsThrownByInnerPublisher() { const int expectedResult = 42; var exceptionToThrow = new PublishException(); var exceptionsThrown = new List <Exception>(); var pendingPublishTask = new TaskCompletionSource <object>(); var innerPublisher = Substitute.For <IResultPublisher>(); innerPublisher.Publish(Arg.Any <Result <int, int> >()) .Returns(call => pendingPublishTask.Task.ContinueWith(_ => { throw exceptionToThrow; })); var fireAndForgetPublisher = new FireAndForgetResultPublisher(innerPublisher, ex => { exceptionsThrown.Add(ex); }); var mock = Substitute.For <IControlCandidate <int, string> >(); mock.Control().Returns(expectedResult); mock.Candidate().Returns(expectedResult); var scientist = new Scientist(fireAndForgetPublisher); var result = scientist.Experiment <int>("myExperiment", experiment => { experiment.Use(mock.Control); experiment.Try(mock.Candidate); }); var whenPublished = fireAndForgetPublisher.WhenPublished(); Assert.False(whenPublished.IsCompleted, "When Published Task completed early."); pendingPublishTask.SetResult(null); await whenPublished; Assert.True(whenPublished.IsCompleted, "When Published Task isn't complete."); Assert.Equal(new List <Exception> { exceptionToThrow }, exceptionsThrown); }
public void RunsBothBranchesOfTheExperimentAndReportsSuccessForInstance() { var mock = Substitute.For <IControlCandidate <int> >(); mock.Control().Returns(42); mock.Candidate().Returns(42); const string experimentName = nameof(RunsBothBranchesOfTheExperimentAndReportsSuccess); var resultPublisher = new InMemoryResultPublisher(); var scientist = new Scientist(resultPublisher); var result = scientist.Experiment <int>(experimentName, experiment => { experiment.Use(mock.Control); experiment.Try("candidate", mock.Candidate); }); Assert.Equal(42, result); mock.Received().Control(); mock.Received().Candidate(); Assert.True(resultPublisher.Results <int>(experimentName).First().Matched); }