chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
+1 vote

Hi, I have following code under test

        public class PlanController
        {
            public void ChangeStatus(int planId)
            {
                var plan = Plan.Load(planId);

                if (plan.Status != PlanStatus.InProgress)
                {
                    throw new NotSupportedException();
                }

                plan.Status = PlanStatus.Locked;
                plan.Update();

                PlanChanges.SaveChanges(plan.Id, plan.Status);
            }
        }

and Test for the ChangeStatus looks like this

        public class PlanControllerTest
        {
            public void ChangeStatus_WhenCalled_StatusIsChangedToLocked()
            {
                // ARRANGE

                const int planId = 1;

                var fakePlan = Isolate.Fake.Instance<Plan>();
                Isolate.WhenCalled(() => fakePlan.Status).WillReturn(PlanStatus.InProgress);

                Isolate.WhenCalled(() => Plan.Load(planId)).WithExactArguments().WillReturn(fakePlan);

                var target = new PlanController();

                // ACT

                target.ChangeStatus(planId);

                // ASSERT

                Isolate.Verify.WasCalledWithExactArguments(() => fakePlan.Status = PlanStatus.Locked);

                Isolate.Verify.WasCalledWithExactArguments(() => fakePlan.Update());

                Isolate.Verify.WasCalledWithExactArguments(() => PlanChanges.SaveChanges(planId, PlanStatus.Locked));
            }
        }

Problem is that test is not strong enough, because if someone changes code under test like this

...
                plan.Status = PlanStatus.Locked;
                plan.Update();

                plan.Status = PlanStatus.InProgress;

                PlanChanges.SaveChanges(plan.Id, plan.Status);
...

the test will still pass, but the PlanChanges.SaveChanges(plan.Id, plan.Status) will be called with wrong status.

 

How to solve this situation? What is the "best practice" approach?

I was thinking about  changing the test to do some kind of condiotional mocking / faking of fakePlan.Status property, so the test would look like this

            public void ChangeStatus_WhenCalled_StatusIsChangedToLocked()
            {
                // ARRANGE

                const int planId = 1;

                var fakePlan = Isolate.Fake.Instance<Plan>();
                Isolate.WhenCalled(() => fakePlan.Status).WillReturn(PlanStatus.InProgress);

                // This is new
                Isolate.WhenCalled(() => { fakePlan.Status = PlanStatus.Locked; }).WithExactArguments().DoInstead((context) =>
                {
                    Isolate.WhenCalled(() => fakePlan.Status).WillReturn(PlanStatus.Locked);
                });

                Isolate.WhenCalled(() => Plan.Load(1)).WithExactArguments().WillReturn(fakePlan);

                var target = new PlanController();

                // ACT

                target.ChangeStatus(planId);

                // ASSERT

                // This is changed
                Assert.That(fakePlan.Status, Is.EqualTo(PlanStatus.Locked));

                Isolate.Verify.WasCalledWithExactArguments(() => fakePlan.Update());

                Isolate.Verify.WasCalledWithExactArguments(() => PlanChanges.SaveChanges(planId, PlanStatus.Locked));
            }

But this fails because on the last line of test 

Isolate.Verify.WasCalledWithExactArguments(() => PlanChanges.SaveChanges(planId, PlanStatus.Locked));

The SaveChanges is called with PlanStatus.InProgress, because it seems that fakePlan.Status is changed to PlanStatus.Locked only for test code and not for method code which is under test.

Thanks for help.

I am using Typemock for C#, v8.6.0.22 and Visual Studio Enterprise 2017, v15.5.6

asked by Ctvt (2.7k points)

Please log in or register to answer this question.

...