Как модульные тесты должны настроить источники данных, если не работающие в сервере приложений?

ОТВЕТ

Моим решением этой проблемы было создание моего собственного подкласса PDFAnnotation.

var isChecked = false

init(forBounds bounds: CGRect, withProperties properties: [AnyHashable : Any]?)

override func draw(with box: PDFDisplayBox, in context: CGContext)

Я использовал свойство isChecked внутри функции рисования. Если свойство было включено, тогда я отображал изображение галочки, которое нашел на Icons8. Мне также пришлось добавить PDFAnnotationHitObserver в мой ViewController и обработать обновление свойства isChecked.

6
задан Mark Meuer 6 May 2009 в 22:12
поделиться

7 ответов

Мне кажется, что весь подход неверен. Если вашему приложению необходимо знать, в каком контейнере оно запущено, вы делаете что-то не так.

Когда я использую Spring, я могу перейти с Tomcat на WebLogic и обратно, ничего не меняя. Я уверен, что при правильной настройке я смогу проделать тот же трюк и с JBOSS. Это цель, к которой я бы стремился.

2
ответ дан 8 December 2019 в 18:41
поделиться

Некоторая комбинация внедрения зависимостей (будь то через Spring, файлы конфигурации или аргументы программы) и Factory Pattern обычно работают лучше всего.

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

4
ответ дан 8 December 2019 в 18:41
поделиться

Все концепция вернулась на передний план. Код более низкого уровня не должен проводить такого рода тестирование. Если вам нужна другая реализация, передайте ее в соответствующем месте.

5
ответ дан 8 December 2019 в 18:41
поделиться

Возможно, что-то вроде этого (уродливо, но может работать)

 private void isRunningOn( String thatServerName ) { 

     String uniqueClassName = getSpecialClassNameFor( thatServerName );
     try { 
         Class.forName( uniqueClassName );
     } catch ( ClassNotFoudException cnfe ) { 
         return false;
     }
     return true;
 } 

Метод getSpecialClassNameFor вернет класс, уникальный для каждого сервера приложений (и может вернуть новый класс. имена при добавлении дополнительных серверов приложений)

Затем вы используете это как:

  if( isRunningOn("JBoss")) {
         createJBossStrategy....etcetc
  }
1
ответ дан 8 December 2019 в 18:41
поделиться
 Контекст ctx = new InitialContext ();
Источник данных dataSource = (DataSource) ctx.lookup (jndiName);

Кто конструирует InitialContext? Его конструкция должна находиться вне кода, который вы пытаетесь протестировать, иначе вы не сможете имитировать контекст.

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

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

public class Foo {
  private final DataSource dataSource;
  public Foo() { // production code calls this - no changes needed to callers
    Context ctx = new InitialContext();
    this.dataSource = (DataSource) ctx.lookup(jndiName);
  }
  public Foo(DataSource dataSource) { // test code calls this
    this.dataSource = dataSource;
  }
  // methods that use dataSource
}

Но прежде чем вы начнете выполнять этот рефакторинг, у вас должны быть некоторые интеграционные тесты, чтобы прикрыть вашу спину. В противном случае вы не сможете узнать, сломают ли что-нибудь даже простые рефакторинги, такие как перемещение поиска DataSource в конструктор. Затем, когда код станет лучше, станет более тестируемым, вы сможете писать модульные тесты. (По определению, если тест касается файловой системы, сети или базы данных, это не модульный тест - это интеграционный тест.)

Преимущество модульных тестов в том, что они выполняются быстро - сотни или тысячи в секунду - и очень сосредоточены на тестировании только одного поведения за раз. Это позволяет запускать тогда часто (если вы не решаетесь запускать все модульные тесты после изменения одной строки, они выполняются слишком медленно), так что вы получаете быструю обратную связь. И поскольку они очень сфокусированы, вы узнаете, просто взглянув на название неудачного теста, где именно в производственном коде находится ошибка.

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

1
ответ дан 8 December 2019 в 18:41
поделиться

Есть несколько способов решить эту проблему. Один из них - передать объект Context классу, когда он находится в модульном тесте. Если вы не можете изменить сигнатуру метода, проведите рефакторинг создания исходного контекста до защищенного метода и протестируйте подкласс, который возвращает фиктивный объект контекста, переопределив метод. Это может, по крайней мере, проверить класс, чтобы вы могли оттуда провести рефакторинг до лучших альтернатив.

Следующий вариант - сделать соединения с базой данных фабрикой, которая может определять, находится ли он в контейнере или нет, и делать соответствующие вещи в в каждом случае.

Одна вещь, о которой следует подумать, - как только у вас будет это соединение с базой данных вне контейнера, что вы собираетесь с ним делать? Это проще, но это не совсем модульный тест, если вам нужно нести весь уровень доступа к данным.

1
ответ дан 8 December 2019 в 18:41
поделиться

Чистый способ сделать это - настроить слушателей жизненного цикла в web.xml . При желании они могут устанавливать глобальные флаги. Например, вы можете определить ServletContextListener в своем web.xml , а в методе contextInitialized установить глобальный флаг, который вы запускаете внутри контейнера. Если глобальный флаг не установлен, значит, вы не работаете внутри контейнера.

-1
ответ дан 8 December 2019 в 18:41
поделиться
Другие вопросы по тегам:

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