1

I have a method which I am using to generate random strings by creating random integers and casting them to char

public static string GenerateRandomString(int minLength, int maxLength)
        {
            var length = GenerateRandomNumber(minLength, maxLength);

            var builder = new StringBuilder(length);

            var random = new Random((int)DateTime.Now.Ticks);

            for (var i = 0; i < length; i++)
            {
                builder.Append((char) random.Next(255));
            }

            return builder.ToString();
        }

The problem is that when I call this method frequently, it is creating the same sequence of values, as the docs already says:

The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random.

As you can see I am making the seed time dependent and also creating a new instance of Random on each call to the method. Even though, my Test is still failing.

[TestMethod]
        public void GenerateRandomStringTest()
        {
            for (var i = 0; i < 100; i++)
            {
                var string1 = Utilitaries.GenerateRandomString(10, 100);
                var string2 = Utilitaries.GenerateRandomString(10, 20);
                if (string1.Contains(string2))
                    throw new InternalTestFailureException("");
            }
        }

How could I make sure that independently of the frequency on which I call the method, the sequence will "always" be different?

Bruno Klein
  • 3,217
  • 5
  • 29
  • 39
  • You simply can't when calling it in such a tight loop. [According to the documentation](http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx) there are 10,000 ticks per millisecond. Your loop probably takes less than that to execute. Therefore, `DateTime.Now.Ticks` will be the same for every iteration. You will probably have to find a webservice or something that gives you a random number... but that won't be quick. – Simon Whitehead Feb 22 '14 at 13:54

3 Answers3

3

Your test is failing because the GenerateRandomString function completes too soon for the DateTime.Now.Ticks to change. On most systems it is quantized at either 10 or 15 ms, which is more than enough time for a modern CPU to generate a sequence of 100 random characters.

Inserting a small delay in your test should fix the problem:

var string1 = Utilitaries.GenerateRandomString(10, 100);
Thread.Sleep(30);
var string2 = Utilitaries.GenerateRandomString(10, 20);
Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

You're effectively doing the same as Random's default constructor. It's using Environment.TickCount. Take a look at the example in this MSDN documentation for the Random constructor. It shows that inserting a Thread.Sleep between the initialization of the different Random instances, will yield different results.

If you really want to get different values, I suggest you change to a seed value that's not time-dependent.

khellang
  • 17,550
  • 6
  • 64
  • 84
1

dasblinkenlight has given why this is happening.

Now you should do this to overcome this problem

public static string GenerateRandomString(Random random , int minLength, 
                                                  int maxLength)
{
    var length = GenerateRandomNumber(random , minLength, maxLength);

    var builder = new StringBuilder(length);   

    for (var i = 0; i < length; i++)
         builder.Append((char) random.Next(255));

    return builder.ToString();
}

public void GenerateRandomStringTest()
{
    Random rnd = New Random();
    for (var i = 0; i < 100; i++)
    {
        var string1 = Utilitaries.GenerateRandomString(rnd, 10, 100);
        var string2 = Utilitaries.GenerateRandomString(rnd, 10, 20);
        if (string1.Contains(string2))
            throw new InternalTestFailureException("");
    }
}
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208