Главная причина для кода модульного теста во-первых состоит в том, чтобы проверить дизайн Вашего кода. Возможно получить 100%-е покрытие кода, но не используя фиктивные объекты или некоторую форму изоляции или внедрения зависимости.
Помнят, модульные тесты не для пользователей, они для разработчиков и систем сборки для использования для проверки системы до выпуска. С этой целью модульные тесты должны работать очень быстро и иметь как можно меньше конфигурацию и трение зависимости. Попытайтесь сделать столько, сколько Вы можете в памяти, и избегать использования сетевых соединений от тестов.
Попробуйте использовать один и тот же случайный объект для всей строки, а не инициализировать по одному для каждого символа.
Случайный объект будет генерировать «псевдослучайное» число на основе математической прогрессии, начиная с от «начального» числа. Фактически вы можете получить одну и ту же последовательность «случайных» чисел, если каждый раз инициализируете объект Random одним и тем же начальным значением.
Теперь, когда вы инициализируете Random без указания начального числа, в качестве начального числа будут использоваться часы компьютера. В этом случае вы, вероятно, делаете это достаточно быстро, чтобы часы не менялись от одной инициализации к другой, и вы всегда получаете одно и то же начальное число.
Лучше инициализировать объект Random в вашей функции, который генерирует случайную строку и передает ее в качестве параметра функции GenerateChar,
Вы можете избавить себя от хлопот и использовать метод Membership.GeneratePassword . По сути, он делает то, что вам нужно.
Использование:
int passwordLength = 5;
int alphaNumericalCharsAllowed = 2;
string random = Membership.GeneratePassword(passwordLength, alphaNumericalCharsAllowed);
Также для удобства чтения вы можете обернуть это вспомогательным методом:
private string GenerateRandomString(int length, int alphaNumericalChars)
{
return Membership.GeneratePassword(length, alphaNumericalChars);
}
Попробуйте static
public string GenerateChar()
{
static Random random = new Random();
return Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))).ToString();
}
Не создавайте новый экземпляр Random
на каждой итерации - это будет заполнять каждый экземпляр текущим временем в миллисекундах, которое, очевидно, вряд ли изменится между итерациями.
Создайте единственный экземпляр Random
и передайте его в метод. Я бы также посоветовал вам не объединять подобные строки в цикл или даже создавать такое количество строк. Кроме того, если вы используете Random.Next (int, int)
, чтобы сделать вашу жизнь намного проще.
Попробуйте следующее:
public char GenerateChar(Random rng)
{
// 'Z' + 1 because the range is exclusive
return (char) (rng.Next('A', 'Z' + 1));
}
public string GenerateString(Random rng, int length)
{
char[] letters = new char[length];
for (int i = 0; i < length; i++)
{
letters[i] = GenerateChar(rng);
}
return new string(letters);
}
private static readonly Random SingleRandom = new Random();
public string GenerateStringNotThreadSafe(int length)
{
return GenerateString(SingleRandom, length);
}
Теперь стоит знать, что Random
не не потокобезопасен, поэтому, если у вас несколько потоков, вам не следует иметь один экземпляр Random
в статической переменной без блокировки. Есть несколько способов обойти это - либо создать подкласс Random
, который является потокобезопасным, либо набор статических методов, которые делают то же самое, либо использовать локальные переменные потока для иметь по одному экземпляру на поток.
У меня есть StaticRandom
класс как часть MiscUtil , но в наши дни я склоняюсь к локальной версии потока и передаю ее вниз цепочку там, где это необходимо. Однажды я добавлю это как еще один вариант в MiscUtil ...
Я знаю, что это может быть не так лучшее решение, но мне нравится идея указать «разрешенные» символы:
private const int _defaultNumberOfCharacters = 8;
private const int _defaultExpireDays = 10;
private static readonly string _allowedCharacters = "bcdfghjklmnpqrstvxz0123456789";
public static string GenerateKey(int numberOfCharacters)
{
const int from = 0;
int to = _allowedCharacters.Length;
Random r = new Random();
StringBuilder qs = new StringBuilder();
for (int i = 0; i < numberOfCharacters; i++)
{
qs.Append(_allowedCharacters.Substring(r.Next(from, to), 1));
}
return qs.ToString();
}
Возможно, вы найдете метод Path.GetRandomFileName
полезным, в зависимости от того, какие именно символы вам нужны в строке.
. Вам следует инициализировать случайную переменную вне метода:
public Random random = new Random();
public string GenerateChar()
{
return Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))).ToString();
}
...
Передайте random
из вызывающего метода и инициализируйте его один раз - вы каждый раз повторно загружаете генератор случайных чисел с одним и тем же начальным числом ....
Nothing special, but short. 32 and 127 are min and max range of chars you want to be generated.
public static string GetRandomString(int length)
{
var r = new Random();
return new String(Enumerable.Range(0, length).Select(n => (Char)(r.Next(32, 127))).ToArray());
}