Отражение Kotlin: findAnnotation < Type > () возвращает ноль

Возможно, возникает соблазн задать вопрос о , как сделать AutoFixture адаптированным к моему дизайну? , но часто более интересным может быть вопрос: как мне сделать мой дизайн более

Вы можете сохранить дизайн и «исправить» AutoFixture, но я не думаю, что это особенно хорошая идея.

Прежде чем я расскажу вам, как это сделать что, в зависимости от ваших требований, возможно, все, что вам нужно сделать, это следующее.

Явное назначение

Почему бы просто не назначить допустимое значение ExpirationDate, как это?

var sc = fixture.Create();
sc.ExpirationDate = sc.ValidFrom + fixture.Create();

// Perform test here...

Если вы используете AutoFixture.Xunit , это может быть еще проще:

[Theory, AutoData]
public void ExplicitPostCreationFix_xunit(
    SomeClass sc,
    TimeSpan duration)
{
    sc.ExpirationDate = sc.ValidFrom + duration;

    // Perform test here...
}

Это довольно устойчиво, потому что даже если AutoFixture ( IIRC) создает случайные значения TimeSpan, они останутся в положительном диапазоне, если вы не сделали что-то для своего fixture, чтобы изменить свое поведение.

Этот подход был бы самым простым способом решения ваших вопрос, если вам нужно проверить SomeClass. С другой стороны, это не очень удобно, если вам нужно SomeClass в качестве входных значений в мириадах других тестов.

В таких случаях может возникнуть соблазн исправить AutoFixture, что также возможно:

Изменение поведения AutoFixture

Теперь, когда вы видели, как решить проблему как одноразовое решение, вы можете сказать AutoFixture об этом как об общем изменении способа SomeClass Сгенерировано:

fixture.Customize(c => c
    .Without(x => x.ValidFrom)
    .Without(x => x.ExpirationDate)
    .Do(x => 
        {
            x.ValidFrom = fixture.Create();
            x.ExpirationDate = 
                x.ValidFrom + fixture.Create();
        }));
// All sorts of other things can happen in between, and the
// statements above and below can happen in separate classes, as 
// long as the fixture instance is the same...
var sc = fixture.Create();

Вы также можете упаковать вышеуказанный вызов на Customize в реализации ICustomization для дальнейшего повторного использования. Это также позволит вам использовать индивидуальный экземпляр Fixture с AutoFixture.Xunit.

Измените дизайн SUT

. В приведенных выше решениях описывается, как изменить поведение AutoFixture , AutoFixture была первоначально написана как инструмент TDD, а основной точкой TDD является предоставление отзывов о тестировании системы (SUT). AutoFixture имеет тенденцию усиливать такую ​​обратную связь, что также имеет место здесь.

Рассмотрим дизайн SomeClass. Ничто не мешает клиенту делать что-то вроде этого:

var sc = new SomeClass
{
    ValidFrom = new DateTime(2015, 2, 20),
    ExpirationDate = new DateTime(1900, 1, 1)
};

Это компилируется и работает без ошибок, но, вероятно, не то, что вы хотите. Таким образом, AutoFixture на самом деле не делает ничего плохого; SomeClass не защищает свои инварианты должным образом.

Это общая ошибка дизайна, где разработчики склонны слишком доверять семантической информации об именах участников. Кажется, мышление заключается в том, что никто в здравом уме не установил бы ExpirationDate значение до ValidFrom! Проблема с таким аргументом заключается в том, что он предполагает, что все разработчики всегда будут присваивать эти значения парами.

Однако клиенты могут также получить экземпляр SomeClass, переданный им, и хотят обновить один значений, например:

sc.ExpirationDate = new DateTime(2015, 1, 31);

Действительно ли это? Как вы можете сказать?

Клиент может посмотреть на sc.ValidFrom, но почему? Целая цель инкапсуляции заключается в том, чтобы освободить клиентов от такого бремени.

Вместо этого вам следует рассмотреть возможность изменения дизайна SomeClass. Наименьшее изменение дизайна, о котором я могу думать, это что-то вроде этого:

public class SomeClass
{
    public DateTime ValidFrom { get; set; }
    public TimeSpan Duration { get; set; }
    public DateTime ExpirationDate
    {
        get { return this.ValidFrom + this.Duration; }
    }
}

Это превращает ExpirationDate в свойство, рассчитанное только для чтения. С этим изменением AutoFixture работает только из коробки:

var sc = fixture.Create();

// Perform test here...

Вы также можете использовать его с AutoFixture.Xunit:

[Theory, AutoData]
public void ItJustWorksWithAutoFixture_xunit(SomeClass sc)
{
    // Perform test here...
}

Это еще немного хрупкий, потому что, хотя по умолчанию AutoFixture создает положительные значения TimeSpan, это также можно изменить.

Кроме того, дизайн фактически позволяет клиентам назначать отрицательные значения TimeSpan свойство Duration:

sc.Duration = TimeSpan.FromHours(-1);

Независимо от того, разрешено ли это, зависит от модели домена. Как только вы начнете рассматривать эту возможность, на самом деле может получиться, что определяющие периоды времени, которые движутся назад во времени, действительны в домене ...

Дизайн согласно Закону Постела

Если проблемный домен - это тот, где возвращение назад во времени не разрешено, вы могли рассмотреть возможность добавления предложения Guard к свойству Duration, отклоняя отрицательные промежутки времени.

Однако, лично я часто обнаруживаю, что я прихожу к лучшему дизайну API, когда серьезно отношусь к закону Postel's . В этом случае почему бы не изменить дизайн так, чтобы SomeClass всегда использовал абсолютный TimeSpan вместо подписанного TimeSpan?

. В этом случае я бы предпочел неизменный объект, который не применяет роли двух экземпляров DateTime до тех пор, пока он не узнает их значения:

public class SomeClass
{
    private readonly DateTime validFrom;
    private readonly DateTime expirationDate;

    public SomeClass(DateTime x, DateTime y)
    {
        if (x < y)
        {
            this.validFrom = x;
            this.expirationDate = y;
        }
        else
        {
            this.validFrom = y;
            this.expirationDate = x;
        }
    }

    public DateTime ValidFrom
    {
        get { return this.validFrom; }
    }

    public DateTime ExpirationDate
    {
        get { return this.expirationDate; }
    }
}

Как и предыдущая редизайн, этот просто работает из коробки с помощью AutoFixture:

var sc = fixture.Create();

// Perform test here...

То же самое происходит с AutoFixture.Xunit, но теперь no клиенты могут неправильно его настроить.

Независимо от того, находите ли вы, что такой дизайн подходит, зависит от вы, но я надеюсь, что, по крайней мере, это пища для размышлений.

0
задан Pascal Ludwig 16 January 2019 в 10:58
поделиться

1 ответ

Foo::password.annotations список аннотаций на имущество. В вашем коде вы использовали @field: use target сайта, что означает, что аннотация применяется к вспомогательному полю, а не к свойству. Поэтому список аннотаций на объекте пуст.

Вариант Java работает, потому что он загружает список аннотаций на поле.

0
ответ дан yole 16 January 2019 в 10:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: