Beispiel #1
0
        private static void SwapFighters(ref ISuperPerson superPerson1, ref ISuperPerson superPerson2)
        {
            ISuperPerson temp = superPerson2;

            superPerson2 = superPerson1;
            superPerson1 = temp;
        }
Beispiel #2
0
 private void CoinTossSwapFighters(ref ISuperPerson superPerson1, ref ISuperPerson superPerson2)
 {
     if (dice.Roll() > (dice.NumberOfSides / 2))
     {
         SwapFighters(ref superPerson1, ref superPerson2);
     }
 }
Beispiel #3
0
        public void WhenFightCalledAndDefenseFighterDoesNotDoCounterDamage_ThenNoDamageDoneToOffenseFighter()
        {
            // Arrange
            int villianHealth = 2;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(52);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on 2nd hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(() => villianHealth);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);
            mockVillian.Setup(x => x.IsAlive).Returns(() => villianHealth > 0);
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() =>
            {
                villianHealth -= 1;
            });

            var mockDice = new Mock <IDice>();

            // Ensure hero gets first hit
            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(1)   //coin toss (false)
            .Returns(1)   //hero gets a hit
            .Returns(1)   //villian failed to block
            .Returns(1)   //villian fails to counter-damage
            .Returns(1)   //villain misses
            .Returns(1)   //hero gets a hit
            .Returns(1);  //villian failed to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Note: Moq example of using Verify with Times.Exactly to count invocations

            // Assert
            mockHero.Verify(x => x.Damage(It.IsAny <int>()), Times.Never());
            mockVillian.Verify(x => x.Damage(It.IsAny <int>()), Times.Exactly(2));
        }
        /// <summary>
        /// Inserts the specified super person into the repository.
        /// </summary>
        /// <param name="superPerson">The super person to insert.</param>
        public void Insert(ISuperPerson superPerson)
        {
            if (superPerson == null)
            {
                throw new ArgumentNullException("superPerson");
            }

            this.context.SuperPeople.Add((SuperPerson)superPerson);
        }
        /// <summary>
        /// Updates the specified super person in the repository.
        /// </summary>
        /// <param name="superPerson">The super person to update.</param>
        public void Update(ISuperPerson superPerson)
        {
            if (superPerson == null)
            {
                throw new ArgumentNullException("superPerson");
            }

            this.context.SetEntityStateModified((SuperPerson)superPerson);
        }
        /// <summary>
        /// Deletes the specified super person from the repository.
        /// </summary>
        /// <param name="superPerson">The super person to delete.</param>
        public void Delete(ISuperPerson superPerson)
        {
            if (superPerson == null)
            {
                throw new ArgumentNullException("superPerson");
            }

            this.context.SuperPeople.Remove((SuperPerson)superPerson);
        }
Beispiel #7
0
        public void WhenFightCalledWithCoinTossFalse_ThenPlayersFirstTurnNotSwapped()
        {
            // Arrange
            bool isVillianAlive = true;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(100);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on any hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);
            mockVillian.Setup(x => x.IsAlive).Returns(() => isVillianAlive);

            // Note: Moq example of using It.IsAny when we don't care about matching the value of the argument
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() => isVillianAlive = false);

            var mockDice = new Mock <IDice>();

            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(49)     //coin toss (false)
            .Returns(1)      //hero hits
            .Returns(1);     //villian fails to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Note: Moq example of using Verify with It.IsAny to count mocked method invocations.

            // Assert
            mockHero.Verify(x => x.Damage(It.IsAny <int>()), Times.Never());
            mockVillian.Verify(x => x.Damage(It.IsAny <int>()), Times.Once());
        }
Beispiel #8
0
        public void WhenFightCalled_ThenFightLogWriteLineCalled()
        {
            // Arrange
            bool isVillianAlive = true;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(100);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on any hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);
            mockVillian.Setup(x => x.IsAlive).Returns(() => isVillianAlive);
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() => isVillianAlive = false);

            var mockDice = new Mock <IDice>();

            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(49)     //coin toss (false)
            .Returns(1)      //hero hits
            .Returns(1);     //villian fails to block

            var mockFightLog = new Mock <IFightLog>();

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            target.FightLog = mockFightLog.Object;

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Assert
            mockFightLog.Verify(x => x.WriteLine(It.IsAny <string>()), Times.AtLeastOnce());
        }
Beispiel #9
0
        public void WhenFightCalledAndHitIsNotBlocked_ThenDamageEqualToStrength()
        {
            // Arrange
            bool isVillianAlive = true;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(52);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on any hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);
            mockVillian.Setup(x => x.IsAlive).Returns(() => isVillianAlive);
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() => isVillianAlive = false);

            var mockDice = new Mock <IDice>();

            // Ensure hero gets first hit
            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(1)   //hero wins coin toss
            .Returns(1)   //hero gets a hit
            .Returns(1);  //villian fails to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Note: Moq example of using Verify with when we care that arguments match exactly.

            // Assert
            mockVillian.Verify(x => x.Damage(52), Times.Once());
        }
Beispiel #10
0
        public void WhenFightCalledWithCoinTossTrue_ThenPlayersFirstTurnSwapped()
        {
            // Arrange
            bool isHeroAlive = true;

            // Weak hero who dies on any damage
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1);
            mockHero.Setup(x => x.Strength).Returns(0);
            mockHero.Setup(x => x.Speed).Returns(0);
            mockHero.Setup(x => x.Resistance).Returns(0);
            mockHero.Setup(x => x.Intellect).Returns(0);
            mockHero.Setup(x => x.IsAlive).Returns(() => isHeroAlive);
            mockHero.Setup(x => x.Damage(It.IsAny <int>())).Callback(() => isHeroAlive = false);

            // Strong, immortal villian
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1000);
            mockVillian.Setup(x => x.Strength).Returns(100);
            mockVillian.Setup(x => x.Speed).Returns(100);
            mockVillian.Setup(x => x.Resistance).Returns(100);
            mockVillian.Setup(x => x.Intellect).Returns(100);
            mockVillian.Setup(x => x.IsAlive).Returns(true);

            var mockDice = new Mock <IDice>();

            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(51)      //coin toss (true)
            .Returns(1)       //villian hits
            .Returns(1);      //hero fails to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Assert
            mockHero.Verify(x => x.Damage(It.IsAny <int>()), Times.Once());
            mockVillian.Verify(x => x.Damage(It.IsAny <int>()), Times.Never());
        }
Beispiel #11
0
        private void TakeTurn(ISuperPerson offenseFighter, ISuperPerson defenseFighter)
        {
            int damage = 0;

            // Determine if fighter1 gets a hit
            int speed = dice.Roll();

            if (speed <= offenseFighter.Speed)
            {
                damage = offenseFighter.Strength;

                //Determine if fighter2 blocks and reduces damage by 50%
                bool wasBlocked = false;
                int  resistance = dice.Roll();
                if (resistance <= defenseFighter.Resistance)
                {
                    damage     = damage / 2;
                    wasBlocked = true;
                }

                this.DispatchDamage(defenseFighter, damage);

                if (!wasBlocked)
                {
                    this.DispatchLog(string.Format("{0} hits {1} with {2} damage.", offenseFighter.Name, defenseFighter.Name, damage));
                }
                else
                {
                    this.DispatchLog(string.Format("{0} hits {1} with {2} partially blocked damage.", offenseFighter.Name, defenseFighter.Name, damage));
                }

                // Verify fighter2 is alive
                if (defenseFighter.IsAlive)
                {
                    // Determine if fighter2 does counterdamage of 50%
                    int intellect = dice.Roll();
                    if (intellect <= defenseFighter.Intellect)
                    {
                        int counterDamage = damage / 2;
                        this.DispatchDamage(offenseFighter, counterDamage);

                        this.DispatchLog(string.Format("{0} counters {1} with {2} damage.", defenseFighter.Name, offenseFighter.Name, counterDamage));
                    }
                }
            }
            else
            {
                this.DispatchLog(string.Format("{0} misses {1}.", offenseFighter.Name, defenseFighter.Name));
            }
        }
Beispiel #12
0
        private void RunFight(ISuperPerson hero, ISuperPerson villian)
        {
            this.DispatchRaiseStarted();

            ISuperPerson offenseFighter = hero;
            ISuperPerson defenseFighter = villian;

            // Who gets the first turn is random
            this.CoinTossSwapFighters(ref offenseFighter, ref defenseFighter);

            // The fight is on
            while (true)
            {
                this.DispatchLog("----------");

                TakeTurn(offenseFighter, defenseFighter);

                this.DispatchLog(string.Format("{0} = {1} health | {2} = {3} health.", hero.Name, hero.Health, villian.Name, villian.Health));

                if ((!hero.IsAlive) || (!villian.IsAlive))
                {
                    Debug.Assert(hero.IsAlive || villian.IsAlive);

                    ISuperPerson winner = hero;
                    ISuperPerson loser  = villian;

                    if (villian.IsAlive)
                    {
                        SwapFighters(ref winner, ref loser);
                    }

                    this.DispatchLog(string.Format("{0} defeated {1}.", winner.Name, loser.Name));
                    winner.Revive();
                    break;
                }

                SwapFighters(ref offenseFighter, ref defenseFighter);
            }

            lock (this.syncLock)
            {
                this.isFightInProgress = false;
            }

            this.DispatchRaiseCompleted();
        }
Beispiel #13
0
        public void WhenFightCalledWithSameHero_ThenThrows()
        {
            // Arrange
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.IsAlive).Returns(true);

            var mockDice = new Mock <IDice>();

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero = mockHero.Object;

            // Act
            target.StartFight(hero, hero);

            // Assert
        }
Beispiel #14
0
        /// <summary>
        /// Starts a fight between the specified hero and villian.
        /// </summary>
        /// <param name="hero">The hero.</param>
        /// <param name="villian">The villian.</param>
        /// <remarks>
        /// This method is often asynchronous and follows the Async event pattern.
        /// </remarks>
        public void StartFight(ISuperPerson hero, ISuperPerson villian)
        {
            if (hero == null)
            {
                throw new ArgumentNullException("hero");
            }

            if (villian == null)
            {
                throw new ArgumentNullException("villian");
            }

            if (object.ReferenceEquals(hero, villian))
            {
                throw new ArgumentException("A hero can not fight themself.", "hero");
            }

            if (!hero.IsAlive)
            {
                throw new ArgumentException("A dead hero can not fight.", "hero");
            }

            if (!villian.IsAlive)
            {
                throw new ArgumentException("A dead villian can not fight.", "villian");
            }

            lock (this.syncLock)
            {
                if (this.isFightInProgress)
                {
                    throw new InvalidOperationException("There is already a fight in progress.");
                }

                this.isFightInProgress = true;
            }

            var action = new Action <ISuperPerson, ISuperPerson>(this.RunFight);

            action.BeginInvoke(hero, villian, null, null);
        }
Beispiel #15
0
        public void WhenFightCalled_ThenFightersTakeTurnsUntilOneDies()
        {
            // Arrange
            int heroHealth    = 4;
            int villianHealth = 3;

            // Hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(100);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(() => heroHealth > 0);
            mockHero.Setup(x => x.Damage(It.IsAny <int>())).Callback(() =>
            {
                heroHealth -= 1;
            });

            // Weak, smart, resistant villian, dies on 2nd hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(() => villianHealth);
            mockVillian.Setup(x => x.Strength).Returns(100);
            mockVillian.Setup(x => x.Speed).Returns(100);
            mockVillian.Setup(x => x.Resistance).Returns(100);
            mockVillian.Setup(x => x.Intellect).Returns(100);
            mockVillian.Setup(x => x.IsAlive).Returns(() => villianHealth > 0);
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() =>
            {
                villianHealth -= 1;
            });

            var mockDice = new Mock <IDice>();

            // Ensure hero gets first hit
            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(1)    //coin toss (false)
            // Hero = 4, Villian = 3
            .Returns(1)    //hero hits
            .Returns(200)  //villian fails to block
            .Returns(200)  //villian fails to do counter-damage
            // Hero = 4, Villian = 2
            .Returns(1)    //villain hits
            .Returns(200)  //hero fails to block
            .Returns(200)  //hero fails to do counter-damage
            // Hero = 3, Villian = 2
            .Returns(1)    //hero hits
            .Returns(200)  //villian fails to block
            .Returns(200)  //villian fails to do counter-damage
            // Hero = 3, Villian = 1
            .Returns(1)    //villain hits
            .Returns(200)  //hero fails to block
            .Returns(200)  //hero fails to do counter-damage
            // Hero = 2, Villian = 1
            .Returns(1)    //hero hits
            .Returns(200)  //villian fails to block
            .Returns(200)  //villian fails to do counter-damage
            // Hero = 2, Villian = 0 (fight should stop here)
            .Returns(1)    //villain hits
            .Returns(200)  //hero fails to block
            .Returns(200); //hero fails to do counter-damage

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Assert
            mockHero.Verify(x => x.Damage(It.IsAny <int>()), Times.Exactly(2));
            mockVillian.Verify(x => x.Damage(It.IsAny <int>()), Times.Exactly(3));
        }
Beispiel #16
0
        public void WhenFightCalled_ThenStartedEventRaised()
        {
            // Arrange
            bool isVillianAlive = true;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(100);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on any hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);

            // Note: Moq example of using lambda's to implement logic on each request
            // Note: Returns(isVillianAlive) wouldn't work here because it would always be tru
            mockVillian.Setup(x => x.IsAlive).Returns(() => isVillianAlive);

            // Note: Moq example of using a callback to modify test-scoped state
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() => isVillianAlive = false);

            var mockDice = new Mock <IDice>();

            mockDice.Setup(x => x.NumberOfSides).Returns(100);

            // Note: Moq example of sequencing a set of returns (different each call)
            mockDice.SetupSequence(x => x.Roll())
            .Returns(49)     //coin toss (false)
            .Returns(1)      //hero hits
            .Returns(1);     //villian fails to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Note: Example of verifying events.
            bool wasStartedRaised = false;

            target.Started += (s, e) =>
            {
                wasStartedRaised = true;
            };

            // Act
            target.StartFight(hero, villian);
            WaitForFightCompleted(target);

            // Assert
            Assert.IsTrue(wasStartedRaised);
        }
Beispiel #17
0
 private void DispatchDamage(ISuperPerson superPerson, int damage)
 {
     this.dispatcher.Invoke(new Action <ISuperPerson, int>((s, d) => { s.Damage(d); }), DispatcherPriority.Render, superPerson, damage);
 }
Beispiel #18
0
        public void WhenFightCalledWhenAFightIsAlreadyInProgress_ThenThrows()
        {
            // Arrange
            bool isVillianAlive = true;

            // Immortal, strong hero
            var mockHero = new Mock <ISuperPerson>();

            mockHero.Setup(x => x.Name).Returns("Hero");
            mockHero.Setup(x => x.Health).Returns(1000);
            mockHero.Setup(x => x.Strength).Returns(100);
            mockHero.Setup(x => x.Speed).Returns(100);
            mockHero.Setup(x => x.Resistance).Returns(100);
            mockHero.Setup(x => x.Intellect).Returns(100);
            mockHero.Setup(x => x.IsAlive).Returns(true);

            // Weak villian, dies on any hit
            var mockVillian = new Mock <ISuperPerson>();

            mockVillian.Setup(x => x.Name).Returns("Villian");
            mockVillian.Setup(x => x.Health).Returns(1);
            mockVillian.Setup(x => x.Strength).Returns(0);
            mockVillian.Setup(x => x.Speed).Returns(0);
            mockVillian.Setup(x => x.Resistance).Returns(0);
            mockVillian.Setup(x => x.Intellect).Returns(0);
            mockVillian.Setup(x => x.IsAlive).Returns(() => isVillianAlive);
            mockVillian.Setup(x => x.Damage(It.IsAny <int>())).Callback(() =>
            {
                // Note: Example of multi-threading awareness when unit testing concurrent operations.
                // Note: Should not confuse unit testing with concurrency race-condition and load testing.

                isVillianAlive = false;
                Thread.Sleep(500);  //sleep here to ensure second call gets a chance before fight completes.
            });

            var mockDice = new Mock <IDice>();

            mockDice.Setup(x => x.NumberOfSides).Returns(100);
            mockDice.SetupSequence(x => x.Roll())
            .Returns(49)     //coin toss (false)
            .Returns(1)      //hero hits
            .Returns(1);     //villian fails to block

            IDice dice = mockDice.Object;
            SlugFestFightStrategy target = new SlugFestFightStrategy(dice);

            ISuperPerson hero    = mockHero.Object;
            ISuperPerson villian = mockVillian.Object;

            // Act
            target.StartFight(hero, villian);

            bool secondCallThrows = false;

            try
            {
                target.StartFight(hero, villian);
            }
            catch (InvalidOperationException)
            {
                secondCallThrows = true;
            }

            WaitForFightCompleted(target);

            // Assert
            Assert.IsTrue(secondCallThrows);
        }