Example #1
0
    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);
    }
Example #4
0
    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();
            }
        }
Example #7
0
    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);
        }