Настроить
Для начала загрузите MRUnit отсюда . После того, как вы извлекли файл tar, перейдите в каталог mrunit-0.9.0-инкубационный / lib. Там вы должны увидеть следующее:
- mrunit-0.9.0-инкубирования-hadoop1.jar
 - mrunit-0.9.0-инкубирования-hadoop2.jar
 
Как я уверен, можно догадаться, что mrunit-0.9.0 -ugating-hadoop1.jar предназначен для MapReduce версии 1 Hadoop, а mrunit-0.9.0-инкубационный-hadoop2.jar предназначен для работы с новой версией Hadoop MapReduce. Для этого поста и для всех остальных мы будем использовать версию hadoop-2.0 из релиза Cloudera CDH4.1.1, поэтому нам понадобится файл mrunit-0.9.0-инкубационный-hadoop2.jar. Я добавил MRUnit, JUnit и Mockito в качестве библиотек в Intellij (JUnit и Mockito находятся в том же каталоге, что и файлы JAR MRUnit). Теперь, когда мы настроили наши зависимости, давайте начнем тестирование.
Тестирование Mappers
Настройка для тестирования маппера очень проста и лучше всего объяснить, посмотрев сначала на некоторый код. Мы будем использовать пример объединения in-mapper из предыдущего поста :
| 
 1 
2 
3 
4 
5 
6 
7 
8 
 | 
@Testpublic void testCombiningMapper() throws Exception {   new MapDriver<LongWritable,Text,Text,TemperatureAveragingPair>()           .withMapper(new AverageTemperatureCombiningMapper())           .withInput(new LongWritable(4),new Text(temps[3]))           .withOutput(new Text('190101'),new TemperatureAveragingPair(-61,1))           .runTest(); } | 
Обратите внимание на свободный стиль API, который добавляет простоту создания теста. Чтобы написать свой тест, вы бы:
- Создание экземпляра класса MapDriver, параметризованного точно так же, как и тестируемый сопоставитель.
 - Добавьте экземпляр Mapper, который вы тестируете, в вызове withMapper.
 - При вызове withInput передайте ключ и входное значение, в этом случае LongWritable с произвольным значением и текстовый объект, содержащий строку из набора погодных данных NCDC, содержащегося в массиве String с именем ‘temps’, который был установлен ранее в тест (здесь не отображается, так как это отнимает от презентации).
 - Укажите ожидаемый результат в вызове withOutput, здесь мы ожидаем объект Text со значением «190101» и объект TemperatureAveragingPair, содержащий значения -61 (температура) и 1 (количество).
 - Последний вызов runTest передает указанные входные значения в маппер и сравнивает фактические выходные данные с ожидаемыми выходными данными, установленными в методе withOutput.
 
Следует отметить, что MapDriver допускает только один ввод и вывод для каждого теста. Вы можете вызывать withInput и withOutput несколько раз, если хотите, но MapDriver перезапишет существующие значения новыми, так что вы будете когда-либо тестировать только один ввод / вывод в любое время. Чтобы указать несколько входных данных, мы бы использовали MapReduceDriver, который был описан позже в нескольких разделах, но далее мы тестируем редуктор.
Тестирование редукторов
Тестирование редуктора происходит по той же схеме, что и тест картографа. Опять же, давайте начнем с примера кода:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
 | 
@Testpublic void testReducerCold(){  List<TemperatureAveragingPair> pairList = new ArrayList<TemperatureAveragingPair>();      pairList.add(new TemperatureAveragingPair(-78,1));      pairList.add(new TemperatureAveragingPair(-84,1));      pairList.add(new TemperatureAveragingPair(-28,1));      pairList.add(new TemperatureAveragingPair(-56,1));      new ReduceDriver<Text,TemperatureAveragingPair,Text,IntWritable>()                .withReducer(new AverageTemperatureReducer())                .withInput(new Text('190101'), pairList)                .withOutput(new Text('190101'),new IntWritable(-61))                .runTest();    } | 
- Тест начинается с создания списка объектов TemperatureAveragingPair, которые будут использоваться в качестве входных данных для редуктора.
 - Создается экземпляр ReducerDriver, и, как и MapperDriver, параметры точно соответствуют тестируемому редуктору.
 - Далее мы передаем экземпляр редуктора, который мы хотим протестировать в вызове withReducer.
 - В вызове withInput мы передаем ключ «190101» и объект pairList, созданный в начале теста.
 - Далее мы указываем вывод, который мы ожидаем, что наш редуктор испустит, тот же ключ «190101» и IntWritable, представляющий среднее значение температур в списке.
 - Наконец, вызывается runTest, который подает нашему редуктору указанные входные данные и сравнивает выходные данные редуктора с ожидаемыми выходными данными.
 
ReducerDriver имеет то же ограничение, что и MapperDriver, — не принимать более одной пары вход / выход. До сих пор мы тестировали Mapper и Reducer по отдельности, но мы также хотели бы протестировать их вместе в интеграционном тесте. Интеграционное тестирование может быть выполнено с использованием класса MapReduceDriver. MapReduceDriver также является классом, который используется для тестирования использования объединителей, пользовательских счетчиков или пользовательских разделителей.
Интеграционное тестирование
Для проверки совместной работы вашего преобразователя и преобразователя MRUnit предоставляет класс MapReduceDriver. Класс MapReduceDriver, как и следовало ожидать, с двумя основными отличиями. Сначала вы параметризуете типы ввода и вывода преобразователя, а также типы ввода и вывода редуктора. Поскольку типы выходных данных маппера должны соответствовать типам входов редуктора, вы получите 3 пары параметризованных типов. Во-вторых, вы можете предоставить несколько входов и указать несколько ожидаемых выходов. Вот наш пример кода:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
 | 
@Testpublic void testMapReduce(){new MapReduceDriver<LongWritable,Text,                      Text,TemperatureAveragingPair,                      Text,IntWritable>()                .withMapper(new AverageTemperatureMapper())                .withInput(new LongWritable(1),new Text(temps[0]))                .withInput(new LongWritable(2),new Text(temps[1]))                .withInput(new LongWritable(3),new Text(temps[2]))                .withInput(new LongWritable(4),new Text(temps[3]))                .withInput(new LongWritable(5),new Text(temps[6]))                .withInput(new LongWritable(6),new Text(temps[7]))                .withInput(new LongWritable(7),new Text(temps[8]))                .withInput(new LongWritable(8),new Text(temps[9]))                .withCombiner(new AverageTemperatureCombiner())                .withReducer(new AverageTemperatureReducer())                .withOutput(new Text('190101'),new IntWritable(-22))                .withOutput(new Text('190102'),new IntWritable(-40))                .runTest();    } | 
Как видно из приведенного выше примера, настройка такая же, как у классов MapDriver и ReduceDriver. Вы передаете экземпляры картографа, редуктора и, необязательно, комбайнера для тестирования. MapReduceDriver позволяет передавать несколько входов с разными ключами. Здесь массив ‘temps’ — это тот же массив, на который ссылаются в образце картографа, и содержит несколько строк из набора данных погоды NCDC, а ключами в этих строках выборки являются месяцы январь и февраль 1901 года, представленные как «190101» и « 190102 ″ соответственно. Этот тест успешен, поэтому мы получаем немного больше уверенности в правильности совместной работы нашего картографа и редуктора.
Вывод
Надеемся, мы доказали, насколько полезным может быть MRUnit для тестирования программ Hadoop. Я хотел бы завершить этот пост некоторыми своими наблюдениями. Хотя MRUnit делает модульное тестирование простым для кода мапперов и редукторов, представленные здесь примеры мапперов и редукторов довольно просты. Если ваша карта и / или сокращенный код начинают становиться более сложными, вероятно, лучше отделить код от инфраструктуры Hadoop и самостоятельно протестировать новые классы. Кроме того, поскольку класс MapReduceDriver полезен для тестирования интеграции, очень легко добраться до точки, когда вы больше не тестируете свой код, а саму платформу Hadoop, что уже было сделано. Я разработал собственную стратегию тестирования, которую я намерен использовать в будущем:
- Модульное тестирование карты / уменьшение кода.
 - Возможно написать один интеграционный тест с классом MapReduceDriver.
 - В качестве проверки работоспособности запустите задание MapReduce при установке на один узел (на моем ноутбуке), чтобы убедиться, что оно выполняется на платформе Hadoop.
 - Затем запустите мой код на тестовом кластере на EC2, используя Apache Whirr в моем случае.
 
Рассказ о том, как настроить установку одного узла на моем ноутбуке (OSX Lion) и установка кластера на EC2 с помощью Whirr, сделает этот пост слишком длинным, поэтому я расскажу об этих темах в следующем. Спасибо за ваше время.
Ресурсы
- Интенсивная обработка данных с MapReduce Джимми Лином и Крисом Дайером
 - Hadoop: полное руководство Тома Уайта
 - Исходный код из блога
 - Hadoop API
 - MRUnit для модульного тестирования Apache Hadoop map уменьшить количество рабочих мест
 - Project Gutenberg — отличный источник книг в текстовом формате, отлично подходящий для локального тестирования заданий Hadoop.
 
Ссылка: Тестирование программ Hadoop с MRUnit от нашего партнера по JCG Билла Бекака в блоге Randomечет о кодировании .