Генерация всех возможных перестановок класса - PullRequest
2 голосов
/ 06 апреля 2009

У меня есть следующие классы. Для целей тестирования я хотел бы получить все возможные перестановки класса Client. Я знаю, что число может быть очень большим, но сейчас это не моя проблема.

Клиент: Нет (int), Имя (строка), Адрес (объект адреса)
Адрес: улица (строка), страна (строка) и т. Д.

Для свойства типа int я всегда пробую одни и те же три значения (-1, 0, 1) для строки (null, string.Empty, "Hello World" и т. Д.). Для базовых типов это работает хорошо. Однако для класса Address это не так.

Вкратце, я пытаюсь написать метод, достаточно универсальный, чтобы использовать любой тип (класс и т. Д.) И получить все возможные перестановки (другими словами: public IEnumerable GetPermutations (Type myType)). С помощью .NET Reflection этот метод будет зацикливаться на всех настраиваемых свойствах.

Кто-нибудь знает, как это сделать?

Спасибо

Ответы [ 6 ]

4 голосов
/ 06 апреля 2009

Среда тестирования PEX делает что-то похожее. В нем делается попытка предоставить несколько вариантов параметров метода, чтобы охватить потенциально полезные контрольные примеры.

2 голосов
/ 06 апреля 2009

Вот класс, который может помочь вам начать, хотя я не очень много тестировал. Обратите внимание, что это будет работать только для классов, которые имеют конструктор без аргументов, и не будет работать для некоторых типов рекурсивных классов (например, класса со свойством своего собственного типа, такого как дерево). Вы также можете предварительно заполнить больше классов в статическом конструкторе.

public static class PermutationGenerator
{
    private static class Permutation<T>
    {
        public static IEnumerable<T> Choices { get; set; }
    }

    static PermutationGenerator()
    {
        Permutation<int>.Choices = new List<int> { -1, 0, 1 }.AsReadOnly();
        Permutation<string>.Choices = new List<string> { null, "", "Hello World" }.AsReadOnly();
    }

    public static IEnumerable<T> GetPermutations<T>()
    {
        if (Permutation<T>.Choices == null) {
            var props = typeof(T).GetProperties().Where(p => p.CanWrite);
            Permutation<T>.Choices = new List<T>(GeneratePermutations<T>(() => Activator.CreateInstance<T>(), props)).AsReadOnly();
        }
        return Permutation<T>.Choices;
    }

    private static IEnumerable GetPermutations(Type t) {
        var method = typeof(PermutationGenerator).GetMethod("GetPermutations", new Type[] {}).MakeGenericMethod(t);
        return (IEnumerable)(method.Invoke(null,new object[] {}));
    }

    private delegate T Generator<T>();

    private static IEnumerable<T> GeneratePermutations<T>(Generator<T> generator, IEnumerable<PropertyInfo> props)
    {
        if (!props.Any())
        {
            yield return generator();
        }
        else
        {
            var prop = props.First();
            var rest = props.Skip(1);

            foreach (var propVal in GetPermutations(prop.PropertyType))
            {
                Generator<T> gen = () =>
                {
                    var obj = generator();
                    prop.SetValue(obj, propVal, null);
                    return (T)obj;
                };
                foreach (var result in GeneratePermutations(gen, rest))
                {
                    yield return result;
                }
            }
        }
    }
}
1 голос
/ 06 апреля 2009

Вы можете взглянуть на PEX

http://research.microsoft.com/en-us/projects/pex/default.aspx

Это инструмент генерации тестов whitebox, который интегрируется в Visual Studio.

1 голос
/ 06 апреля 2009

Большинство нетривиальных динамически размещаемых объектов, таких как строки, не имеют конечного количества различных «перестановок», в которых они могут находиться. Эта строка может быть столько, сколько вы хотите, до тех пор, пока не закончится ваша ОЗУ.

Так что это действительно сизифова задача, и, как указано, нет смысла ее выполнять, если вы не наложите гораздо более жесткие ограничения на то, какие перестановки вы ищете.

0 голосов
/ 06 апреля 2009

Как уже говорили многие, генерация всех перестановок невозможна в вычислительном отношении для нетривиальных классов. То, что я должен был сделать и имел большой успех, - это генерировать все перестановки класса для определенного диапазона входных данных; то есть, учитывая класс со свойствами A, B и C, я бы хотел сгенерировать все перестановки A = 1, A = 2, B = 1, C = 3 и C = 4, в результате чего:

A = 1, B = 1, C = 3

A = 2, B = 1, C = 3

A = 1, B = 1, C = 4

A = 2, B = 1, C = 4

Такого рода вещи могут быть выполнены с помощью рекурсивных алгоритмов или некоторых действительно элегантных запросов LINQ. Здесь есть довольно исчерпывающая часть здесь , но это хороший объем программирования, и он действительно помогает, если вы одержимы своей теорией множеств.

0 голосов
/ 06 апреля 2009

Это все равно что просить перенести Великую китайскую стену за 1 час в космос. Это не может быть сделано.

Вам необходимо знать, что определяет каждую перестановку каждого типа, даже типов, которые вы не создавали, и это невозможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...