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 EquatableRelationTuple(new WrappedString(str1),
new WrappedString(str2),
new WrappedString(str3));
tuple.It_should_fulfill_IEquatable_standards();
}
}
Do tych testów pomocna będzie nam Tupla i Checker (2 dodatkowe wrappery).
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