Assume the following requirements:
Is it a good idea to use the Composite design-pattern for this, taking into account that there will be:
- Only 1
TestPlan
- a
TestPlan
can only haveTestSequence
s - a
TestSequence
can only haveTest
s - a
Test
can only haveAssert
s
I've started coding using the Composite pattern but I got the feeling that this pattern cannot enforce the above rules. Is my feeling correct and should I use another design (pattern) here? Or is using the composite pattern here correct but is my implementation of it just wrong?
public abstract class TestElement
{
public TestElement(int id)
{
this.Id = id;
}
public virtual void Add(TestElement element)
{
throw new NotImplementedException();
}
public virtual void Remove(TestElement element)
{
throw new NotImplementedException();
}
public virtual IEnumerable<TestElement> GetElements()
{
throw new NotImplementedException();
}
public virtual TestElement GetElement(int index)
{
throw new NotImplementedException();
}
public string Id { get; private set; }
public abstract void Setup();
public abstract void Teardown();
}
public class TestPlan : TestElement
{
// Here TestElement should only be of type TestSequence
private IList<TestElement> Children = new List<TestElement>();
public TestPlan(int id)
: base(id)
{
}
public override void Add(TestElement element)
{
this.Children.Add(element);
}
public override void Remove(TestElement element)
{
this.Children.Remove(element);
}
public override TestElement GetElement(int index)
{
return this.Children.ElementAt(index);
}
public override IEnumerable<TestElement> GetElements()
{
return this.Children;
}
public override void Setup()
{
Console.WriteLine("Setup executed for TestPlan " + Id);
}
public override void Teardown()
{
Console.WriteLine("Teardown executed for TestPlan " + Id);
}
}
public class TestSequence : TestElement
{
// Here TestElement should only be of type Test
private IList<TestElement> Children = new List<TestElement>();
public TestSequence(int id)
: base(id)
{
}
public override void Add(TestElement element)
{
this.Children.Add(element);
}
public override void Remove(TestElement element)
{
this.Children.Remove(element);
}
public override TestElement GetElement(int index)
{
return this.Children.ElementAt(index);
}
public override IEnumerable<TestElement> GetElements()
{
return this.Children;
}
public override void Setup()
{
Console.WriteLine("Setup executed for TestSequence " + Id);
}
public override void Teardown()
{
Console.WriteLine("Teardown executed for TestSequence " + Id);
}
}
public class Test : TestElement
{
// Here TestElement should only be of type Assert
private IList<TestElement> Children = new List<TestElement>();
public Test(int id)
: base(id)
{
}
public override void Add(TestElement element)
{
this.Children.Add(element);
}
public override void Remove(TestElement element)
{
this.Children.Remove(element);
}
public override TestElement GetElement(int index)
{
return this.Children.ElementAt(index);
}
public override IEnumerable<TestElement> GetElements()
{
return this.Children;
}
public override void Setup()
{
Console.WriteLine("Setup executed for Test " + Id);
}
public override void Teardown()
{
Console.WriteLine("Teardown executed for Test " + Id);
}
}
public class Assert : TestElement
{
public Assert(int id)
: base(id)
{
}
public override void Setup()
{
throw new NotSupportedException("No setup with Assert.");
}
public override void Teardown()
{
throw new NotSupportedException("No teradown with Assert.");
}
public bool ExecuteAssert()
{
return true;
}
}