Decorate NBuilder to create Repeatable Sequential Generator

Background

In the previous post I had demonstrated the use of NBuilder to generate sequential data. This approach works fine if we need a sequence with continuous numbers. There are occasions when we need a sequence which resets or repeats itself at periodic interval.
For eg. if we are assigning the day of week number to a list, we would want to reset the day after it reaches 7. Same way if we are writing a piece of code which counts the number of overs in an cricket match, we would want to reset the counter after 6 legitimate deliveries.
For this demo, I would like to reuse the earlier example of person entity and a repository to access the list of persons. Lets assume I want to build a repeatable sequential list which has a minimum and maximum limit. If the order is ascending order for the generator we would like to reset the sequence to start at the minimum value once it reaches the upper bound. Also the reverse is possible i.e. if we are building a list in descending order, once we reach the lower bound, we should reset the counter to the maximum value.

Use Decorator pattern to create Repeatable Sequential Generator

With the above requirements in mind, let me try customizing the SequentialGenerator class provided by NBuilder. The SequentialGenerator class in NBuilder provides a Generate method which is used to generate the next number in the sequence based on the increment factor. But it does not provide a capability to reset the counter if we needed to as explained above.
The SequentialGenerator class provides 2 virtual methods StartingWith and Advance which we can override. Advance method advances the sequence by the increment factor while the StartingWith is used to set the initial value from where the sequencing should start.
I can use the Decorator pattern to add functionality to the sequential generator class by checking for the boundary conditions. Assuming I have a ascending sequence, I would like to restart the sequence if the max value is reached. For that reason, I can check in the Advance method if the result of Generate is going to exceed the upper bound. If that happens I can reset the sequence and start it from the minimum value using the StartingWith method. For the purpose of implementing the Decorator pattern, I’ll inherit my class named RepeatableSequentialGenerator from the SequentialGenerator class.
public class RepeatableSequentialGenerator : SequentialGenerator<int>
    {
        private readonly SequentialGenerator<int> generator;

        private int maxValue = int.MaxValue;

        private int minValue = int.MinValue;

        public new int Increment
        {
            get
            {
                return this.generator.Increment;
            }

            set
            {
                this.generator.Increment = value;
            }
        }
        public new GeneratorDirection Direction
        {
            get
            {
                return this.generator.Direction;
            }

            set
            {
                this.generator.Direction = value;

                this.generator.StartingWith(value == GeneratorDirection.Ascending ? this.minValue : this.maxValue);
            }
        }

        public RepeatableSequentialGenerator()
        {
            this.generator = new SequentialGenerator<int>();
        }

        public RepeatableSequentialGenerator(int minValue, int maxValue)
        {
            this.minValue = minValue;
            this.maxValue = maxValue;
            this.generator = new SequentialGenerator<int>();
        }

        public int MaxValue
        {
            get
            {
                return this.maxValue;
            }

            set
            {
                this.maxValue = value;
            }
        }

        public int MinValue
        {
            get
            {
                return this.minValue;
            }

            set
            {
                this.minValue = value;
            }
        }

        protected override void Advance()
        {
            int current = this.generator.Generate();

            if (this.Direction == GeneratorDirection.Ascending)
            {
                if (current > this.maxValue)
                {
                    this.generator.StartingWith(this.minValue);
                    current = this.generator.Generate();
                }
            }
            else
            {
                if (current < this.minValue)
                {
                    this.generator.StartingWith(this.maxValue);
                    current = this.generator.Generate();
                }
            }

            base.StartingWith(current);
        }

        public override void StartingWith(int nextValueToGenerate)
        {
            if (this.generator != null)
            {
                this.generator.StartingWith(nextValueToGenerate);
            }
        }
    }


In order to decorate the SequentialGenerator class, I need to create an instance of that within my class. If you look at the complete source code, you can also see that I am overriding the properties for Direction and Increment. These two properties act as wrappers to get or set the values on the internal sequential generator object.


protected override void Advance()
        {
            int current = this.generator.Generate();

            if (this.Direction == GeneratorDirection.Ascending)
            {
                if (current > this.maxValue)
                {
                    this.generator.StartingWith(this.minValue);
                    current = this.generator.Generate();
                }
            }
            else
            {
                if (current < this.minValue)
                {
                    this.generator.StartingWith(this.maxValue);
                    current = this.generator.Generate();
                }
            }

            base.StartingWith(current);
        }


The advance method does the trick for us. It checks what is the order of the sequence (Ascending / Descending). Based on the direction it resets the sequence if its above or below the bounds. Another point to note above is that I am doing all the calculations on the encapsulator generator class but finally calling the base.StartingWith(current). If we don’t do this, the value doesn’t get returned to the calling program.


The below test validates the logic


[TestMethod()]
        public void GetAllTest_ShouldReturn_SequntialPersonIds_InAscendingOrder()
        {
            const int minValue = 1;
            const int maxValue = 4;

            RepeatableSequentialGenerator repeatableSequentialGenerator = new RepeatableSequentialGenerator(minValue, maxValue);
            repeatableSequentialGenerator.Direction = GeneratorDirection.Ascending;

            const int numberOfPersons = 10;

            IList<PersonEntity> persons = Builder<PersonEntity>.CreateListOfSize(numberOfPersons)
                .WhereAll().Have(x => x.Id = repeatableSequentialGenerator.Generate())
                .Build();

            personRepository.Persons = persons.ToList();

            IList<PersonEntity> result = personRepository.GetAll();

            Assert.AreEqual(numberOfPersons, result.Count, "Expected and actual count is not same");
            Assert.AreEqual(result[0].Id, 1);
            Assert.AreEqual(result[1].Id, 2);
            Assert.AreEqual(result[3].Id, 4);
            Assert.AreEqual(result[7].Id, 4);
            Assert.AreEqual(result[9].Id, 2);
        }





You can see that we are using the repeatableSequentialGenerator instance for generating the sequence. I have set the minimum value to 1 and maximum value to 4. So I assume that the 4th element in the persons list will have the Id as 4 and the last one will have Id as 2. I have also verified that the intermediate values are as expected.


This is a simple case. I want to check if the increment factor works correctly or not. Below is the test which does that


[TestMethod()]
        public void GetAllTest_ShouldReturn_SequntialPersonIds_InAscendingOrder_IncludingIncrement()
        {
            RepeatableSequentialGenerator repeatableSequentialGenerator = new RepeatableSequentialGenerator(1, 5);
            repeatableSequentialGenerator.Direction = GeneratorDirection.Ascending;
            repeatableSequentialGenerator.Increment = 2;

            const int numberOfPersons = 10;

            IList<PersonEntity> persons = Builder<PersonEntity>.CreateListOfSize(numberOfPersons)
                .WhereAll().Have(x => x.Id = repeatableSequentialGenerator.Generate())
                .Build();

            personRepository.Persons = persons.ToList();

            IList<PersonEntity> result = personRepository.GetAll();

            Assert.AreEqual(numberOfPersons, result.Count, "Expected and actual count is not same");
            Assert.AreEqual(result[0].Id, 1);
            Assert.AreEqual(result[1].Id, 3);
            Assert.AreEqual(result[2].Id, 5);
            Assert.AreEqual(result[9].Id, 1);
        }


In this case I have set the bounds as 1 and 5 and the increment factor as 2. So I am verifying that the top 3 elements Ids are 1, 3 and 5 respectively. Also I confirm that the last element has the Id set to 1.


Finally i also check whether the repeatable sequence works in descending mode or not.


[TestMethod()]
        public void GetAllTest_ShouldReturn_SequntialPersonIds_InDescendingOrder()
        {
            RepeatableSequentialGenerator repeatableSequentialGenerator = new RepeatableSequentialGenerator(1, 4);
            repeatableSequentialGenerator.Direction = GeneratorDirection.Descending;


            const int numberOfPersons = 10;

            IList<PersonEntity> persons =
                Builder<PersonEntity>.CreateListOfSize(numberOfPersons).WhereAll().Have(
                    x => x.Id = repeatableSequentialGenerator.Generate()).Build();

            personRepository.Persons = persons.ToList();

            IList<PersonEntity> result = personRepository.GetAll();

            Assert.AreEqual(numberOfPersons, result.Count, "Expected and actual count is not same");
            Assert.AreEqual(result[0].Id, 4);
            Assert.AreEqual(result[9].Id, 3);
        }

In this test I have changes the direction of the sequence to descending. The bounds are set to 1 and 4. So in the verification section, I verify that the 1st element’s Id has the upper bound value which is 4 in this case. I also verify that the last element has the value as 3.

Conclusion



I wanted to keep the post short and sweet but it turned out to be a bit lengthy one. I just wanted to show how easy it is to extend NBuilder to suite our requirements. Using Decorator Pattern helped me to add functionality to the SequentialGenerator without making any changes to the existing code.


I have uploaded the complete source code to http://dl.dropbox.com/u/1569964/RepeatableSequentialGenerator.zip. If you have any comments feel free to put them down and provide me feedback.


Until next time Happy programming :)


spacer

Generate Sequences and Random data using NBuilder

Background

In mu earlier post on how to use NBuilder to generate test data, I had demonstrated few basic features of NBuilder. I had also mentioned that I will be doing a follow up post on other features that this dll provides. In this post I’ll be demonstrating the sequencing and random pick list features. I’ll be reusing the classes from the previous post.

How to use NBuilder to generate Sequence data

In our PersonEntity class we have the Id property. Assume that we have an requirement to use the running serial number for this property. Since our PersonRepository will be returning a list when we call the GetAll method, we can apply the sequencing logic in this method.

NBuilder has a notion of SequentialGenerator. This is similar to setting an identitty column in the database schema. We can specify the increment and the direction to the constructor of this class. We can also set the initial value from where we would like to start the sequence.

[TestMethod()]
        public void GetAllTest_ShouldReturn_SequntialPersonIds()
        {
            SequentialGenerator<int> sequenceGenerator = new SequentialGenerator<int> { Direction = GeneratorDirection.Ascending, Increment = 1 };

            const int numberOfPersons = 10;

            IList<PersonEntity> persons = Builder<PersonEntity>.CreateListOfSize(numberOfPersons)
                .WhereAll().Have(x => x.Id = sequenceGenerator.Generate())
                .Build();

            personRepository.Persons = persons.ToList();

            IList<PersonEntity> result = personRepository.GetAll();

            Assert.AreEqual(numberOfPersons, result.Count, "Expected and actual count is not same");
            Assert.AreEqual(result[0].Id, 1);
        }


As can be seen from the above code snippet, I have set the direction as Ascending and the increment as 1. I have also set the Id property to be the sequence number generated from Generate() method. If you run this test, it fails. I was assuming that the first item in the collection will have the Id as 1. But my assumption was wrong.



Please note that we need to set the starting value before we can all the Generate method.



sequenceGenerator.StartingWith(1);


On rerunning the test, it passes successfully.



How to use NBuilder to generate Random data



Assume that the functionality is the reverse of what was implemented above. Now we need to use random numbers instead of a sequence. NBuilder again comes to the rescue. Take a look at the following code snippet



[TestMethod()]
        public void GetAllTest_ShouldReturn_RandomPersonIds()
        {
            RandomGenerator randomGenerator = new RandomGenerator();

            const int minimumId = 5;
            const int maximumId = 50;
            const int numberOfPersons = 10;

            IList<PersonEntity> persons = Builder<PersonEntity>.CreateListOfSize(numberOfPersons)
                .WhereAll().Have(x => x.Id = randomGenerator.Next(minimumId, maximumId))
                .Build();

            personRepository.Persons = persons.ToList();

            IList<PersonEntity> result = personRepository.GetAll();

            Assert.AreEqual(numberOfPersons, result.Count, "Expected and actual count is not same");

            bool lessThanMinimum = result.Any(person => person.Id < minimumId);
            bool greaterThanMaximum = result.Any(person => person.Id > maximumId);

            Assert.IsFalse(lessThanMinimum);
            Assert.IsFalse(greaterThanMaximum);
        }


On this occasion I am creating the instance of RandomGenerator. Random generator has very good support for randomizing many of the primitive types. I have set the upper and lower bounds between 5 and 50. So the Ids will be assigned between these two bounds. I verify that the result does not contain any Id which is beyond these two bounds using the last two lines of the code.



Conclusion



My initial thoughts were that I wanted to cover another feature related to picking of random data from a pre defined list. I’ll leave it for another time. In the future post I also intend to demonstrate the Fluent Dates and the custom naming capabilities. I have been advocating the use of NBuilder in all our tests wherever we need to generate dummy data.



Hope this was helpful. I have uploaded the complete source code to http://dl.dropbox.com/u/1569964/SequenceAndPickUsingNBuilder.zip.



Until next time Happy Programming.

spacer