Как я могу вставлять свойства конфигурации в единичный тест, используя SpringBoot2, JUnit5 и Kotlin

this - одна из неправильно понятых концепций в JavaScript, потому что она ведет себя совсем не так, как с места на место. Просто this ссылается на «владельца» функции, которую мы сейчас выполняем.

this помогает получить текущий объект (контекст выполнения a.k.a.), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, что текущий this is

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Выше мы создаем 3 переменные с одинаковым именем «val». Один в глобальном контексте, один внутри obj и другой внутри innerMethod obj. JavaScript разрешает идентификаторы в определенном контексте, поднимая цепочку областей действия из локального глобального.


Несколько мест, где this можно дифференцировать

Вызов метода объекта

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Когда line1, JavaScript устанавливает контекст выполнения (EC) для вызова функции, устанавливая this объекту, на который ссылается все, что было до последнего «.». поэтому в последней строке вы можете понять, что a() был выполнен в глобальном контексте, который является window.

С конструктором

this можно использовать для ссылки на создаваемый объект

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Когда выполняется новый Person(), создается совершенно новый объект. Вызывается Person и его this установлен для ссылки на этот новый объект.

Вызов функции

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Если мы пропустим ключевое слово new, whatIsThis ссылается на самый глобальный контекст, он может найти (window)

С обработчиками событий

Если обработчик события является встроенным, this ссылается на глобальный объект




При добавлении обработчика событий через JavaScript, this относится к элементу DOM, который генерирует событие.


0
задан Nephthys76 13 July 2018 в 16:37
поделиться

2 ответа

Я вижу ошибку в следующей строке:

@ContextConfiguration(classes = [AmazonS3Config::class, VqsS3FileReader::class])

Пожалуйста, введите здесь configuration классы (а не только бобы).

Short-hot исправить тест

Создать класс (если отсутствует), например VqsS3Configration в основном модуле (например, в модуле, где у вас есть производственный код)

Создать класс, например VqsS3TestConfigration, в том же пакете с ваши тесты. Содержимое этого файла:

@org.springframework.context.annotation.Configuration // mark, that this is configuration class
@org.springframework.context.annotation.Import(VqsS3Configration::class) // it references production configuration from test configuration
@org.springframework.context.annotation.ComponentScan // ask Spring to autoload all files from the package with VqsS3TestConfigration and all child packages
class VqsS3TestConfigration {
   /*put test-related beans here in future*/
}

Затем перейдите к тесту и измените объявление:

@ContextConfiguration(classes = [VqsS3TestConfigration ::class]) // we ask Spring to load configuration here

Я создал образец приложения здесь: https://github.com/ imanushin / spring-boot2-junit5-and-kotlin-integration

Пожалуйста, используйте строку .\gradlew.bat test или gradlew.bat bootRun в папке src. Тест проверит, что мы можем читать свойства. bootRun будет печатать автоматически загруженные свойства

Теория расточки

Прежде всего - Spring имеет классы конфигурации - они необходимы для загрузки и инициализации других классов. Вместо классов Service или Comonent основная цель классов конфигурации - просто создавать сервисы, компоненты и т. Д.

Если мы упростим алгоритм загрузки приложения Spring, это будет следующим:

  1. Найти классы конфигурации
  2. Прочитать их аннотацию, понять список классов (например, дерево ссылок), которые должны быть загружены (и, кроме того, как они должны быть загружены)
  3. Загружать классы разными способами:

3.1. Для классов, которые аннотируются с помощью @ConfigurationProperties, введите здесь пункты конфигурации

3.2. Для классов, которые аннотируются с помощью @RestController, зарегистрируйте их как контроллеры отдыха

3.N. и т. д. ...

Как понимает Spring, какая конфигурация должна быть загружена?

  1. Формально это делается Spring Boot, однако я назову ее как Spring
  2. Понимать несколько исходных конфигураций - их можно поместить в класс SpringApplicationBuilder в тестовые аннотации (см. выше), в контекст XML и т. д. В нашем случае мы используем тестовую аннотацию и @ContextConfiguration атрибут
  3. Рекурсивный получить всю импортированную конфигурацию (например, Spring читает @Import аннотацию, затем она получает детей, затем проверяет их импорт и т. д.).
  4. Используйте Spring Заводы для автоматической настройки конфигурации из jar

Поэтому в нашем случае Spring будет делать такие действия:

  1. Получить конфигурацию из тестовой аннотации
  2. Получите все остальные конфигурации рекурсивным способом
  3. Загрузите все классы в контур
  4. Запустите тест
0
ответ дан Manushin Igor 17 August 2018 в 12:24
поделиться
  • 1
    Я могу создать репозиторий github с образцом, если вам нужно – Manushin Igor 13 July 2018 в 17:14
  • 2
    Манушин спасибо ... Я думаю, что я понимаю большую часть того, что вы говорите, но я внес изменения, и теперь тест пытается развернуть мой контекст, не соблюдая мой заданный профиль пружины. (Другими словами, он использует мой профиль по умолчанию вместо моего тестового профиля и, следовательно, пытается запустить Flyway и начать мой БД) – Nephthys76 13 July 2018 в 20:22
  • 3
    @ Nephthys76, это странно ... Я разместил здесь пример приложения - github.com/imanushin/spring-boot2-junit5-and-kotlin-integration . Я попытался минимизировать его, поэтому он демонстрирует только свойства приложения – Manushin Igor 15 July 2018 в 19:20

Хорошо, это заняло у меня весь день, но я, наконец, получил свои свойства приложения для загрузки в мой тестовый контекст. Я сделал 2 изменения:

Во-первых, я добавил аннотацию @Service к моей службе VqsS3FileReader, которую я изначально забыл. Кроме того, хотя я обновил свой тест, чтобы не вводить AmazonS3Config через конструктор, я забыл обновить мою службу, чтобы сделать то же самое. Поэтому я изменил

следующее:

class VqsS3FileReader(val amazonS3Config: AmazonS3Config) : VqsFileReader {
    companion object: mu.KLogging()
...

:

@Service
class VqsS3FileReader : VqsFileReader {
    companion object: mu.KLogging()

    @Resource
    private lateinit var amazonS3Config: AmazonS3Config
...

Наконец, я изменил свои аннотации Spring на мой тест.

из этого:

@ActiveProfiles("test")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SpringExtension::class)
@ContextConfiguration(classes = [AmazonS3Config::class, VqsS3FileReader::class])
class VqsS3FileReaderTest(): TestBase() {
...

к этому:

@ActiveProfiles("test")
@SpringBootTest
@ComponentScan("com.ilmn.*")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SpringExtension::class)
@EnableAutoConfiguration
@SpringJUnitConfig(SpringBootContextLoader::class)
class VqsS3FileReaderTest(): TestBase() {
...

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

0
ответ дан Nephthys76 17 August 2018 в 12:24
поделиться
Другие вопросы по тегам:

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