public class WrappedString : IEquatable<WrappedString> { public string StringValue { get; set; } public WrappedString(string stringValue) { StringValue = stringValue; } public bool Equals(WrappedString other) { return this.StringValue == other.StringValue; } }Każda klasa implementująca IEquatable<WrappedString> powinna spełniać parę standardów, m.in. jeżeli T jest strukturą to domyślna wartość powinna zwrócić tą samą wartość, a kiedy obiekt klasy porównujemy do null zawsze powinna zwracać fałsz.
public abstract class EquatableRelation<TType> where TType : IEquatable<TType> { public abstract TType GetItemX(); //object to test private bool IsValueType() { return typeof (TType).IsValueType; } #region Default values protected virtual void It_should_return_false_because_comparing_to_null() { if (!IsValueType()) { TType number1 = GetItemX(); Assert.IsFalse(number1.Equals(null)); } } protected virtual void It_should_return_true_for_default_value_in_valueType() { if (IsValueType()) { var value1 = default(TType); var value2 = default(TType); Assert.IsTrue(value1.Equals(value2)); } } #endregion }
Obiekt powinien spełniać warunki relacji równoważności.
public abstract class EquatableRelation<TType> where TType : IEquatable<TType> { public abstract TType GetItemX(); public abstract TType GetItemY(); public abstract TType GetItemZ(); #region relation //relacja zwrotna protected virtual void It_should_be_reflexive_relation() { TType number1 = GetItemX(); if (!IsValueType()) { Assert.IsNotNull(number1); } Assert.IsTrue(number1.Equals(number1)); } //relacja symetryczna protected virtual void It_should_be_symmetric_relation() { TType number1 = GetItemX(); TType number2 = GetItemY(); bool number1To2 = number1.Equals(number2); bool number2To1 = number2.Equals(number1); Assert.AreEqual(number1To2, number2To1); } //relacja przechodnia protected virtual void It_should_be_Transitive_relation() { TType number1 = GetItemX(); TType number2 = GetItemY(); TType number3 = GetItemZ(); Assert.IsTrue(number1.Equals(number2)); Assert.IsTrue(number2.Equals(number3)); Assert.IsTrue(number1.Equals(number3)); } #endregion }Oprócz tego zawsze powinno się zwracać taką samą wartość porównania:
public abstract class EquatableRelation<TType> where TType : IEquatable<TType> { private const int NumberOfRepeatedTestRuns = 10; protected virtual void It_should_return_always_the_same_value_for_Equals() { var bools= new List<bool>(); for (int i = 0; i < NumberOfRepeatedTestRuns; i++) { TType number1 = GetItemX(); TType number2 = GetItemY(); bools.Add(number1.Equals(number2)); } Assert.IsTrue(bools.All(x => x)); } protected virtual void It_should_return_always_the_same_value_for_reflexive() { var bools= new List<bool>(); for (int i = 0; i < NumberOfRepeatedTestRuns; i++) { TType number1 = GetItemX(); TType number2 = GetItemX(); bools.Add(number1.Equals(number2)); } Assert.IsTrue(bools.All(x => x)); } protected virtual void It_should_return_always_true_for_default_values_in_valueType() { if (IsValueType()) { for (int i = 0; i < NumberOfRepeatedTestRuns; i++) { var value1 = default(TType); var value2 = default(TType); Assert.IsTrue(value1.Equals(value2)); } } } }Oraz w różnym czasie domyślna wartość powinna zwracać tą samą wartość
public abstract class EquatableRelation<TType> where TType : IEquatable<TType> { protected virtual void It_should_return_always_the_same_value_for_default_value_in_valueType_for_diffrent_timeTics() //super długa nazwa { if (IsValueType()) { Random r= new Random(12345); var defaultvalues = new List<TType>(); for (int i = 0; i < NumberOfRepeatedTestRuns; i++) { Thread.Sleep(r.Next(100,500)); defaultvalues.Add(default(TType)); } Assert.IsTrue(defaultvalues.All(x => x.Equals(default(TType)))); } } }Ok, to teraz masz standardy jakie powinien spełniać każdy obiekt implementujący IEquatable<WrappedString>. Możemy do tego stworzyć interfejs z tym standardem.
public interface IStandardEquatable { void It_should_fulfill_IEquatable_standards(); } public abstract class EquatableRelation<TType> :IStandardEquatable where TType : IEquatable<TType> { public virtual void It_should_fulfill_IEquatable_standards() { It_should_return_true_for_default_value_in_valueType(); It_should_return_false_because_comparing_to_null(); It_should_be_reflexive_relation(); It_should_return_always_the_same_value_for_reflexive(); It_should_be_coreflexive_relation_because_same_value(); It_should_return_always_the_same_value_for_Equals(); It_should_be_symmetric_relation(); It_should_be_Transitive_relation(); It_should_return_always_the_same_value_for_default_value_in_valueType(); It_should_return_always_true_for_default_values_in_valueType(); It_should_return_always_the_same_value_for_default_value_in_valueType_for_diffrent_timeTics(); } }A nasz pierwszy abstrakcyjny test
public abstract class EquatableRelationTest<TType> : EquatableRelation<TType> where TType : IEquatable<TType> { [Test, Explicit("Run test which are required for standardization")] public override void It_should_fulfill_IEquatable_standards() { base.It_should_fulfill_IEquatable_standards(); } }Jeżeli będziesz chciał przetestować int to możesz:
[TestFixture] public class IntEquatableTest : EquatableRelationTest<int> { public override int GetItemX() { return 1; } public override int GetItemY() { return 1; } public override int GetItemZ() { return 1; } }Tak samo dla WrappedString
[TestFixture] public class WrappedStringEquatableTest : EquatableRelationTest<WrappedString> { public override WrappedString GetItemX() { return new WrappedString("Abc"); } public override WrappedString GetItemY() { return new WrappedString("Abc"); } public override WrappedString GetItemZ() { return new WrappedString("Abc"); } }Można skorzystać z TestCasów
[TestFixture] public class WrappedStringEquatableTest3 { [TestCase("Abc", "Abc", "Abc")] [TestCase("Abc ", "abc", "Abc")] public void It_should_be_eq(string str1, string str2, string str3) { IEqStdFulfillable tuple = new EquatableRelationTupleDo tych testów pomocna będzie nam Tupla i Checker (2 dodatkowe wrappery).(new WrappedString(str1), new WrappedString(str2), new WrappedString(str3)); tuple.It_should_fulfill_IEquatable_standards(); } }
public class EquatableRelationTuple<T> : Tuple<T, T, T>, IStandardEquatable where T : IEquatable<T> { private readonly EquatableRelationChecker<T> checker; public EquatableRelationTuple(T item1, T item2, T item3) : base(item1, item2, item3) { checker = new EquatableRelationChecker<T>(item1, item2, item3); } public void It_should_fulfill_IEquatable_standards() { checker.It_should_fulfill_IEquatable_standards(); } } public class EquatableRelationChecker<T> : EquatableRelation<T> where T : IEquatable<T> { private readonly T _vakue1; private readonly T _value2; private readonly T _value3; public EquatableRelationChecker(T value1, T value2, T value3) { _vakue1 = value1; _value2 = value2; _value3 = value3; } public override T GetItemX() { return _vakue1; } public override T GetItemY() { return _value2; } public override T GetItemZ() { return _value3; } }
Brak komentarzy:
Prześlij komentarz