简体   繁体   中英

Comparing two objects with Visual Studio Unit Testing Framework

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);
    }
}

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
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM