0

I'm using TDD to develop an Android mobile game with Unity. I isolated the core logic inside normal classes. Currently, I'm intend to test the following scenario : Player or AI activates the "End turn" option and the game manager goes to the next character waiting for its turn.

I tried to use AreEqual, AreNotEqual, AreSame, AreNotSame methods from the framework. AreSame and AreNotSame returned with failed. AreEquals and AreNotEquals returned with the following exception: "AssertFailException". I verified by debbuging my test that both references are not null. I have overridden the Equals and GetHashCode from compare 2 objects and made sure that the class I'm trying to check in my test implemented the interface IEqualityComparer. I'm trying to figure out what's wrong but I can't. Basically my test is doing the following :

  1. Generating the game manager
  2. Generating the characters of the game
  3. Add two sample characters to the list of characters
  4. Creating an EndTurnCommand object
  5. Activate the first player
  6. Make the first player call end turn and activate the next character (second sample character)
  7. Compare previous active character and current and make sure that they're not the same

Below you can find the TestMethod

        var gm = new Assets.GameCoreLogic.Managers.GameManager();
        gm.GenerateCharacters();
        var characGen = new CharacterGenerator();
        var stats = new BaseCharacterStats();
        stats.StatGeneration(500, 1, 1, 1, 1, 1, 1, 1);
        var charac = characGen.Generate(new Health((int)stats.HealthPoints), stats, PlayerDirection.Down);
        var secondCharac = characGen.Generate(new Health((int)stats.HealthPoints+1), stats, PlayerDirection.Up);
        gm.EveryCharacters.Add(charac);
        gm.EveryCharacters.Add(secondCharac);
        var gcm = new GameCommandMenu();
        var etc = new EndTurnCommand(gcm);
        gm.ActivatePlayer(0);
        var active = gm.ActivePlayer;
        etc.Execute(active,gm);
        Assert.AreNotSame(active, gm.ActivePlayer);

To make sure that the TestMethod can make sense for readers, I'm putting the source code for EndTurnCommand (Command Pattern object), BaseCharacter(with properties and the override methods), the Generate method from CharacterGenerator.

EndTurnCommand

    public class EndTurnCommand: CharacterActions
{
    public EndTurnCommand(IReceiver receiver) : base(receiver)
    {
    }

    public void Execute(BaseCharacter caller, GameManager manager)
    {
        if (caller == null)
            throw new ArgumentException();            
        if(manager == null)
            throw new ArgumentException();

        manager.GoToNextCharacter();
    }
}

BaseCharacter

    public class BaseCharacter: IEqualityComparer<BaseCharacter>
{
    public BaseCharacterStats BaseStats { get; set; }
    public Health Health { get; set; }
    public PlayerDirection Direction;
    public List<BaseEnemy> CurrentEnnemies;
    public List<BaseCharacter> TeamMembers;
    public int MovementPoints = 4;
    public GameMap GameMap;
    public Cell CurrentCoordinates;
    public bool IsDead; //Testing

    public BaseCharacter(Health health = null, BaseCharacterStats stats = null, PlayerDirection direction = default(PlayerDirection))
    {
        BaseStats = stats;
        Health = health;
        Direction = direction;
        CurrentEnnemies = new List<BaseEnemy>();
        TeamMembers = new List<BaseCharacter>();
    }

    public bool Equals(BaseCharacter x, BaseCharacter y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;

        return x.IsDead == y.IsDead &&
               x.Health.CurrentHealth == y.Health.CurrentHealth &&
               x.Health.StartingHealth == y.Health.StartingHealth &&
               x.BaseStats.Power == y.BaseStats.Power &&
               x.BaseStats.Defense == y.BaseStats.Defense &&
               x.BaseStats.MagicPower == y.BaseStats.MagicPower &&
               x.BaseStats.MagicResist == y.BaseStats.MagicResist &&
               x.BaseStats.Luck == y.BaseStats.Luck &&
               x.BaseStats.Speed == y.BaseStats.Speed &&
               x.BaseStats.Agility == y.BaseStats.Agility &&
               x.Direction == y.Direction;
    }

    public int GetHashCode(BaseCharacter obj)
    {
        var hashCodeStats = obj.BaseStats?.GetHashCode() ?? 0;
        var hasCodeHealth = obj.Health?.GetHashCode() ?? 0;
        var hasCodeDirection = obj.Direction.GetHashCode();
        return hashCodeStats ^ hasCodeHealth ^ hasCodeDirection;
        }
}

CharacterGenerator

public class CharacterGenerator
{
    public BaseCharacter Generate(Health h, BaseCharacterStats bcs, PlayerDirection pd)
    {
        return new BaseCharacter(h,bcs,pd);
    }
}
Community
  • 1
  • 1
Kevin Avignon
  • 2,853
  • 3
  • 19
  • 40
  • When AssertFailedException happen, it means the values are not as you expected. Which means active and gm.ActivePlayer get computed and does not return equal = true. I would start by just compare a few status like return x.IsDead == y.IsDead, maybe do it in GetHashCode too just simply return int and see the behavior is. Then keep on adding conditions. – TLJ Nov 14 '15 at 20:31
  • What should I do in the GetHashCode? What I was doing was not correct? And hum, basically, you're telling to remove the status I'm checking in my override Equals until I find the one causing a false? Should I remove that check or just don't use it? But doing so., would it be a bad check? @TLJ – Kevin Avignon Nov 14 '15 at 21:00
  • I think GetHashCode() is used when you put your class in a Dictionary. Nothing wrong on your implement. I was just saying maybe scope down your problem a bit. I usually use Assert.AreEqual(x,y) to do these type of test. Oh you can just simply put a debug point in your Equal to see which statement went wrong. – TLJ Nov 14 '15 at 21:06

1 Answers1

1

Can you try to change your Equals signature to this?

public override bool Equals(object obj)
{
    BaseCharacter that = (BaseCharacter)obj;
    return this.IsDead == that.IsDead
        && this.Health.CurrentHealth == that.Health.CurrentHealth;
}

== updated ==

I went ahead an implement a simple class and a test case. Maybe it's easier for you to spot the difference.

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            XCharacter x = new XCharacter() { isDead = true, Health = 100 };
            YCharacter y1 = new YCharacter() { isDead = true, Health = 100};
            YCharacter y2 = new YCharacter() { isDead = true, Health = 0 };
            Assert.AreEqual(x, y1); //ok 
            Assert.AreNotEqual(x, y2); //ok
            Assert.AreEqual(x,y2); // not ok
        }
    }

    public abstract class BaseCharacter
    {
        public bool isDead { get; set; }
        public int Health { get; set; }

        public override bool Equals(object obj)
        {
            BaseCharacter that = (BaseCharacter)obj;
            return this.isDead == that.isDead && this.Health == that.Health;
        }
    }

    public class XCharacter : BaseCharacter
    {
    }

    public class YCharacter : BaseCharacter
    {
    }
}
TLJ
  • 4,525
  • 2
  • 31
  • 46
  • Do I have to implement the interface IEqualityComparer ? – Kevin Avignon Nov 14 '15 at 23:20
  • No you don't have to. Did you try to put break point and see if it exec the function? – TLJ Nov 14 '15 at 23:53
  • When I debug it and put breaks points in the Equals method, it does not break.Moreover, when I tried ArreEqual, it passes. But it should pass on AreNotEqual. – Kevin Avignon Nov 15 '15 at 00:07
  • Equals method should be called by the AreEqual function. Double check your function signature. putting `override` keyword will help you spot the error. Let me know the result! – TLJ Nov 15 '15 at 00:11
  • Hmm, quick question: In my game, if I have two instances of the same class (Healer), and they currently have the same stats, will they be equal? If I have Healer and Warrior with the same everything, I don't want them to be equals, because they're two different types child from the base class. – Kevin Avignon Nov 15 '15 at 04:43
  • It's all up to you. If you want 2 instance of healers to be different, simply check reference. If you want them to be equal, check their stats. You can add GetType() to your Equals function to prevent Warriors that has the same stat with the healer become equal. something like this this.getType == that.getType() – TLJ Nov 15 '15 at 05:09