У них есть реализация класса геометрической формы, которая выглядит примерно так:

    private readonly IShapeModel _shape;

    public Shape(IShapeModel shape) : base(shape)
    {
        _shape = shape;
    }

    /// <summary>
    /// Specific geometry data of the shape
    /// </summary>
    public string GeometryData => _shape.GeometryData;

    /// <summary>
    /// Returns the <see cref="Geometry"/> for this shape
    /// </summary>
    public Geometry Geometry => Geometry.Parse(GeometryData);

Как видите, я предоставляю фигуре модель и позволяю ей возвращать объект Geometry с помощью стандартного метода Parse, предоставляемого Geometry.

Код работает отлично и возвращает пустую геометрию, если GeometryData не задано.

Теперь я хочу проверить это примерно так:

    [TestMethod]
    public void AccessGeometryPropertyWithNoGeometryDataSetShouldReturnEmpty()
    {
        var shape = new TestShapeModel {GeometryData = null};
        _shapeViewModel = new Shape(shape);
        var expected = Geometry.Empty;
        var actual = _shapeViewModel.Geometry;
        Assert.AreEqual(expected, actual);
    }

Хотя проблема в том, что Geometry.Empty, похоже, возвращает новый экземпляр, который не равен результату экземпляра Parsed.

Хотя оба объекта идентичны. Я получаю такой результат: Дополнительная информация: Ошибка Assert.AreEqual. Ожидается: <>. Актуально: <>.

Когда я придумал это:

    [TestMethod]
    public void AccessGeometryPropertyWithNoGeometryDataSetShouldReturnEmpty()
    {
        var shape = new TestShapeModel {GeometryData = null};
        _shapeViewModel = new Shape(shape);
        Assert.IsTrue(IsEmptyGeometry(_shapeViewModel.Geometry));
    }

    /// <summary>
    /// Check if Geometry is empty by comparing Empty Bounds.
    /// </summary>
    private static bool IsEmptyGeometry(Geometry geometry)
    {
        var result = false;
        var expected = Geometry.Empty;
        if (geometry != null)
        {
            result = (geometry.Bounds == expected.Bounds);
        }
        return result;
    }

Есть ли лучший подход для решения этой проблемы? Я ожидал, что что-то в самой структуре будет сравниваться с Geometry.Empty без переопределения Equals или реализации приведенного выше кода.

0
Edward Pieper 28 Апр 2016 в 15:32

2 ответа

Лучший ответ

Если Geometry не реализован вами вообще, вы можете взять свой метод IsEmptyGeometry и сделать его методом расширения и использовать его, чтобы сделать ваше Утверждение «красивым» способом.

public static class GeometryExtensions
{
    public static bool IsEmpty(this Geometry geometry)
    {
        var result = false;
        var expected = Geometry.Empty;

        if (geometry != null)
        {
            result = (geometry.Bounds == expected.Bounds);
        }

        return result;
    }
}

Тогда вместо этого:

    [TestMethod]
    public void TestEmptyGeometry()
    {
        var shape = new TestShapeModel { GeometryData = null };
        _shapeViewModel = new Shape(shape);
        var expected = Geometry.Empty;
        var actual = _shapeViewModel.Geometry;
        Assert.AreEqual(expected, actual);
    }

Вы могли сделать это:

    [TestMethod]
    public void TestEmptyGeometry()
    {
        var shape = new TestShapeModel { GeometryData = null };
        _shapeViewModel = new Shape(shape);
        var actual = _shapeViewModel.Geometry;
        Assert.IsTrue(actual.IsEmpty());
    }
1
Ismael 28 Апр 2016 в 13:42

Assert.Equals использует равное сравнение между объектами, поэтому вы должны переопределить метод Equals объекта System.Object, чтобы он работал, сравнивая два объекта Geometry. Я не знаю вашей реализации геометрии, поэтому я собираюсь предположить, как работает существенное, исходя из того, что вы объяснили.

Я предполагаю, что то, что делает одну геометрию похожей на другую, - это то, что они имеют одинаковые границы. В вашем случае это должно быть сложнее, поэтому рассмотрим это на моем примере.

Вот подсказка, что делать в вашем классе Geometry.

public class Geometry
{
    // I don't know what is the implementation of bounds, so 
    // I'm just assuming that is something comparable here.
    public Rectangle Bounds { get; set; }

    // Here's your definition of Geometry.Empty, from what I understood.
    public static Geometry Empty
    {
        get
        {
            return new Geometry { Bounds = new Rectangle(0, 0, 0, 0) };
        }
    }

    // Here is the key: you must override the default operators of equality
    // and difference to make comparations to work, because internally it will
    // use them.
    public static bool operator ==(Geometry left, Geometry right)
    {
        if (left == null && right == null)
        {
            return true;
        }

        if (left != null && right != null)
        {
            return left.Bounds == right.Bounds;
        }

        return false;
    }

    public static bool operator !=(Geometry left, Geometry right)
    {
        if (left == null && right == null)
        {
            return false;
        }

        if (left != null && right != null)
        {
            return left.Bounds != right.Bounds;
        }

        return true;
    }

    // I recommend you to override Equals method of
    // System.Object too. For Assert.AreEqual to work,
    // actually this method will be used.
    public override bool Equals(object obj)
    {
        var objAsGeometry = obj as Geometry;

        if (obj == null)
        {
            return false;
        }

        return objAsGeometry.Bounds == this.Bounds;
    }

    // GetHashCode is used in some types of comparations too,
    // altough not in your case with Assert.AreEqual.
    // If you want to make a fully comparable object, 
    // be sure to override it too, with all conditions used
    // to compare one Geometry object with other.
    public override int GetHashCode()
    {
        return Bounds.GetHashCode();
    }
}

Таким образом, тест, сравнивающий два объекта Geometry.Empty, должен пройти:

[TestClass]
public class GeometryTests
{
    [TestMethod]
    public void TestTwoEmptyGeometries()
    {
        var geometry1 = Geometry.Empty;
        var geometry2 = Geometry.Empty;

        // Pass
        Assert.AreEqual(geometry1, geometry2);
    }
}
0
Ismael 28 Апр 2016 в 12:59