Как провести модульное тестирование алгоритмов, которым нужно загружать данные с жесткого диска (картинки, в данном случае!)? - PullRequest
3 голосов
/ 21 августа 2010

Intro

Я делаю своего рода приложение OCR, которое должно распознавать символы на основе предварительно сохраненных изображений .bmp каждого символа.

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

class CharacterFactory : ICharacterFactory {
    private Collection<Bitmap> aPictures = new HashTable<Bitmap>();
    private Collection<Bitmap> bPictures = new HashTable<Bitmap>();
    private Collection<Bitmap> cPictures = new HashTable<Bitmap>();
    ...

    public CharacterFactory() {
        LoadAllPictures();
    }

    ...    

    public Character GetCharacter(Bitmap characterToRecognize) {
        if (aPictures.Contains(characterToRecognize)) return new ACharacter();
        if (bPictures.Contains(characterToRecognize)) return new BCharacter();
        if (cPictures.Contains(characterToRecognize)) return new BCharacter();
        ...
    }
}

У меня вопрос

как провести модульное тестирование этого класса?Единственный способ проверить класс, который я вижу, - это действительно сохранить пару растровых изображений для передачи аргумента characterToRecognize и сравнить их со списком предварительно сохраненных изображений, которые есть в моей программе.Конечно, в этом есть проблема, заключающаяся в том, что требуется некоторое время для загрузки изображений и другое время для запуска алгоритма GetCharacter ().

Конечно, я мог бы обернуть каждую коллекцию xPictures моей CharacterFactory в новый классно я просто перенесу проблему в этот новый класс.

Как справляться с подобными ситуациями?

Ответы [ 4 ]

1 голос
/ 23 августа 2010

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

  1. Растровое изображение не переопределяет Equals для сравнения данных изображения; Contains () будет основано на равенстве ссылок, что, вероятно, не то, что вам нужно. Вам необходимо предоставить собственную реализацию, если вы хотите выполнить равенство содержимого изображения.

  2. Прямое сравнение, скорее всего, не будет работать из-за сглаживания. Вам также необходимо решить, как найти символы, которым вы хотите соответствовать.

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

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

1 голос
/ 21 августа 2010

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

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

1 голос
/ 22 августа 2010

Проблема, конечно, в том, что BitMap (как и многие классы .Net) запечатан.Что мешает вам создавать насмешки.В этих случаях я обычно делаю очень тонкую оболочку для этих классов, которая принимает BitMap для конструктора, а затем имитирует методы и делегаты для BitMap.тогда вы можете сделать макет этого класса или извлечь для него интерфейс.Затем заставьте класс, который вы хотите протестировать, взять новый «IBitMap» и смоделировать его, внедрить свои данные ext, как говорили другие.

Мои проекты часто заканчиваются небольшой коллекцией этих «Microsoft Wrappers».Было бы намного проще, если бы они просто включали интерфейсы для этих классов или, по крайней мере, не закрывали их.

1 голос
/ 21 августа 2010

Тест, который зависит от любых внешних данных, не является модульным тестом. Это интеграционный тест.

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

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