Создание пользовательских проверок Lint в Android

  1. Четыре части к каждой проверке ворса
  2. Реализация
  3. Проблема
  4. Детектор
  5. тестирование
  6. Тестирование детектора
  7. Выполнение тестов
  8. Линти Фреш

Lint - это инструмент статического анализа, который может помочь выявить ошибки и проблемы в программном проекте. Хотя он существует уже много лет, Lint остается вневременным инструментом, который был перенесен на множество различных платформ. Android Lint имеет более 200 различных проверок, начиная от неясных улучшений производительности и заканчивая проблемами безопасности и даже проблемами интернационализации.

Немного поиска, вы можете найти исходный код для всех существующие проверки Android Lint , Просматривайте на свой страх и риск - это редко документированный неконечный колеблющийся адский ландшафт API.

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

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

Четыре части к каждой проверке ворса

Каждая проверка Lint состоит из четырех основных частей: реализации, проблемы, детекторы и реестр. Мы рассмотрим каждый из них более подробно позже, но вот основы:

  • Проблемы - проблема является возможной проблемой или ошибкой в ​​приложении Android. Это то, что проверяет Lint, например, избыточные макеты XML или забывчивость о запуске Launcher. Каждый раз, когда запускается Lint и возвращается список возможных проблем; это проблемы.
  • Детекторы - Детектор просматривает ваш код в поисках проблем. Один детектор может выполнять поиск по нескольким независимым, но связанным проблемам, таким как поиск нескольких проблем с манифестом Android с помощью одного детектора.
  • Реализации - Реализация связывает Проблему с определенным классом Детектора, а также указывает, где искать данную Проблему. Например, Реализация может сказать Детектору, предназначенному для проверки проблем макета, искать только в определенных файлах XML.
  • Реестры - Реестр - это список всех проблем, которые Lint позаботится при запуске. Все проблемы по умолчанию, проверяемые Lint, перечислены в классе BuiltinIssueRegistry. Поскольку мы будем писать наши нестандартные проблемы, нам также придется предоставить наш собственный реестр, который будет включен в наш окончательный пакетный JAR-вывод.

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

Реестр - это просто список всех его проблем, но все остальные части могут быть воспроизведены и использованы повторно. Итак, вернемся к нашему примеру проверки Lint, которая ищет использование Enum, нам нужно будет создать несколько частей:

  • Проблема, которая заключает в себе идею использования Enum
  • Детектор, который может искать в Java-файлах объявление Enum
  • Реализация, которая указывает на наш новый Детектор и предоставляет Область для поиска (все файлы Java)
  • Реестр, который содержит список всех наших новых проблем (список только с одним элементом)

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

Вы должны создать собственный детектор Lint в своем собственном модуле Android Studio или даже в своем собственном проекте, чтобы проверка Lint могла использоваться повторно и не привязывалась к конкретному проекту. Для начала давайте добавим несколько строк в наши зависимости build.gradle:

Зависимости {compile 'com.android.tools.lint: lint: 24.3.1' compile 'com.android.tools.lint: lint-api: 24.3.1' compile 'com.android.tools.lint: lint-проверок: 24.3.1 '}

Теперь мы можем погрузиться в детали.

Реализация

Реализация нашей проверки Lint является частью проблемы, указывающей на класс Detector и набор Scope. Без Реализации Проблема не знала бы, как быть идентифицированной или где искать проблему.

Вот пример из EnumDetector.java:

закрытый статический финал класса <? extends Detector> DETECTOR_CLASS = EnumDetector. класс ; приватный статический финал EnumSet <Scope> DETECTOR_SCOPE = Scope. JAVA_FILE_SCOPE; приватная статическая конечная реализация IMPLEMENTATION = новая реализация (DETECTOR_CLASS, DETECTOR_SCOPE);

Есть два параметра, о которых нужно позаботиться:

  • Класс детектора - указывает на детектор, который будет использовать наша реализация. В этом примере мы укажем на наш пользовательский класс EnumDetector.java, который просматривает наш код для Enums (мы рассмотрим его более подробно позже). Тип параметра Детектор - Класс <? extends Detector>, поэтому мы можем использовать любой пользовательский класс, который происходит от предоставленного суперкласса Detector.
  • Scope Set - Scope - это EnumSet <Scope>, который описывает набор областей действия файлов, в которых может быть обнаружена Проблема. Возможности включают (но не ограничиваются ими) файлы ресурсов, исходные файлы Java, файлы классов Java, файлы конфигурации Proguard Android Manifest файлы и все файлы в проекте. Важно ограничить область видимости как можно более узкой. Например, если проблема появляется только в манифесте Android, не используйте Scope.ALL, а вместо этого Scope.MANIFEST_SCOPE. Если Lint используется для каждого файла автоматически (например, в среде IDE), то ограничение Scope улучшит производительность, позволив Lint проверять наличие проблем только в пределах этого файла. В нашем случае поиска по Enum мы устанавливаем Scope равным Scope.JAVA_FILE_SCOPE, поскольку Enums будут определены только в исходном файле Java.

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

Проблема

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

Следующий фрагмент кода является примером проблемы, определенной в EnumDetector.java:

приватная статическая final String ISSUE_ID = "Enum"; private static final String ISSUE_DESCRIPTION = "Избегать использования перечислений"; private static final String ISSUE_EXPLANATION = "Ни один настоящий программист на Android никогда не должен использовать перечисления. НИКОГДА." ; private static final Категория ISSUE_CATEGORY = Категория. ПРЕДСТАВЛЕНИЕ ; private static final int ISSUE_PRIORITY = 5; private static final Серьезность ISSUE_SEVERITY = Серьезность. ВНИМАНИЕ; public static final Issue ISSUE = Проблема. create (ISSUE_ID, ISSUE_DESCRIPTION, ISSUE_EXPLANATION, ISSUE_CATEGORY, ISSUE_PRIORITY, ISSUE_SEVERITY, IMPLEMENTATION // Это было определено в разделе «Реализации»);

Как показано выше, мы создаем пользовательскую проблему с помощью статического метода create () со следующими параметрами:

  • Идентификатор - каждая проблема имеет постоянное значение идентификатора, которое должно быть кратким, описательным и уникальным среди всех проблем. Идентификатор никогда не должен быть нулевым. Общее соглашение состоит в том, чтобы просто использовать одно слово в верблюжьей шкуре.
  • Описание - описание представляет собой краткую однострочную сводку проблемы, используемую для того, чтобы дать общее представление о том, что касается этой проблемы.
  • Объяснение . Объяснение - это более подробное описание проблемы, подробно объясняющее пользователю, что оно означает. Параметр description, как правило, слишком краткий, чтобы передать подробности проблемы Lint, поэтому объяснение - это то, где вы объясняете полностью и предоставляете контекст. Объяснение всегда отображается в выводе HTML для проверки Lint, хотя его также можно интегрировать в инструментальные средства Lint среды IDE.
  • Категория - категория - это группа, в которую попадает проблема. Предопределено несколько категорий, и категории также могут быть вложенными для действительно определенных проблем. Категории полезны, потому что пользователь может фильтровать и сортировать Проблемы, что позволяет включать или исключать Проблемы в заданном запуске Lint для каждой категории.
  • Приоритет - Приоритет - это числовое ранжирование того, насколько важна проблема. Рейтинг используется для сравнения, ранжирования и сортировки вопросов. Рейтинг варьируется от 1 до 10, 10 из которых являются наиболее важными.
  • Серьезность . Серьезность определяет, насколько серьезной является проблема в смысле сборки и компиляции с возможными фатальными, ошибочными, предупреждающими или игнорируемыми возможностями. Фатальные и серьезность ошибок считаются ошибками сборки. Неустранимые проблемы считаются чуть более серьезными, так как они будут проверяться автоматически при сборке APK. Если обнаружена фатальная проблема, то сборка отменяется. Предупреждение - самая распространенная серьезность, и она все еще позволяет сборке быть успешной. Любые проблемы со степенью игнорирования не проверяются.
  • Реализация - это то же самое, что вы видели ранее: Реализация указывает на класс детектора проблемы, а также дает набор области действия, где проблема применима.

Идентификатор, описание и объяснение - все описываемые значения, относящиеся к Enums, в то время как категория, приоритет и серьезность имеют предопределенные значения, выбранные из их соответствующих классов. Мы выбрали категорию производительности, потому что использование Enum может негативно повлиять на производительность приложения, и мы дали ей приоритет 5 из 10, потому что это не так важно. Серьезность Предупреждения означает, что сборка все еще пройдет, но будет помечена как потенциальная проблема. Заполнение метода builder - это все, что нужно для создания нашей собственной проблемы!

Тем не менее, сердце проверки Lint лежит в другом месте: в детекторе.

Детектор

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

Детектор реализует один из интерфейсов сканера, который дает ему возможность сканировать код. Три возможности - XmlScanner, JavaScanner и ClassScanner, используемые для файлов XML, файлов Java и файлов классов соответственно. Если мы хотим обнаружить проблему в манифесте Android, мы будем использовать интерфейс XmlScanner. Чтобы найти Enums, мы будем использовать JavaScanner.

Различные сканеры выполняют поиск по коду через API lombok.ast, который представляет код как Абстрактное синтаксическое дерево или АСТ. Вместо строк кода вы получаете доступное для поиска дерево. Ломбок предоставляет утилиты и хуки для разбора этих деревьев, что позволяет вам находить определенные фрагменты кода, которые вам небезразличны для ваших проблем.

Без лишних слов, вот остальная часть файла EnumDetector.java, который включает в себя все тяжелые работы для проверки Lint:

Открытый класс EnumDetector расширяет Detector и реализует Detector. JavaScanner {... // Код реализации и выдачи сверху / ** * Создает новую проверку {@link EnumDetector} * / public EnumDetector () {} @Override public boolean applyTo (контекстный контекст @NonNull, файл файла @NonNull) {верни истину; } @Override public EnumSet <Scope> getApplicableFiles () {return Scope. JAVA_FILE_SCOPE; } @Override public List &lt;Class <? extends Node >> getApplicableNodeTypes () {return Arrays. &lt;Class <? расширяет узел >> asList (EnumDeclaration. class); } @Override public AstVisitor createJavaVisitor (@NonNull JavaContext context) {возврат нового EnumChecker (context); } закрытый статический класс EnumChecker extends ForwardingAstVisitor {закрытый финальный JavaContext mContext; public EnumChecker (контекст JavaContext) {mContext = context; } @Override public boolean visitEnumDeclaration (узел EnumDeclaration) {mContext. отчет (ISSUE, Location. create (mContext. file), ISSUE. getBriefDescription (TextFormat. TEXT)); вернуть супер. visitEnumDeclaration (узел); }}}

Давайте разберемся с этим. Детектор создается Lint каждый раз, когда мы запускаем проверку Lint, подобно тому, как JUnit разрушает и перестраивает все между выполнениями. Чтобы позволить Lint автоматически создавать экземпляр вашего детектора, мы предоставляем открытый конструктор по умолчанию. Технически, компилятор Java предоставит его вам автоматически, если вы его опустите, но мы определим наш явно как напоминание о том, что система его использует.

Вот методы снова:

@Override public boolean applyTo (контекстный контекст @NonNull, файл файла @NonNull) {return true; }

Метод applyTo (...) является ловушкой, чтобы определить, является ли данный файл допустимым и должен ли быть отсканирован, и мы возвращаем true, чтобы проверить все в нашем данном Scope.

@Override public EnumSet <Scope> getApplicableFiles () {return Scope. JAVA_FILE_SCOPE; }

Метод getApplicableFiles () определяет область действия нашего детектора, который для этого примера является всеми файлами Java.

@ Переопределить общедоступный список &lt;Class <? extends Node >> getApplicableNodeTypes () {return Arrays. &lt;Class <? расширяет узел >> asList (EnumDeclaration. class); }

Метод getApplicableNodeTypes () - это то, где вещи становятся интересными. «Узлом» в этом смысле является определенный сегмент или фрагмент кода. Узел может быть объявлением класса или вызовом метода или даже комментарием. Мы заботимся только о конкретном случае объявления Enum, поэтому мы возвращаем список одного действительного типа узла: EnumDeclaration.class.

@Override public AstVisitor createJavaVisitor (@NonNull JavaContext context) {вернуть новый EnumChecker (context); }

Теперь, когда наш Детектор знает, что нужно применять только к файлам Java и подключаться только к узлам объявления Enum, следующий шаг - пройти по нашему дереву и поразить узлы один за другим. Метод createJavaVisitor (...) - это наш метод Lombok для обхода нашего Java-дерева. Мы создаем внутренний класс с именем EnumChecker, чтобы представить процесс проверки этого дерева для узлов, которые нам нужны:

закрытый статический класс EnumChecker extends ForwardingAstVisitor {закрытый финальный JavaContext mContext; public EnumChecker (контекст JavaContext) {mContext = context; } @Override public boolean visitEnumDeclaration (узел EnumDeclaration) {mContext. отчет (ISSUE, Location. create (mContext. file), ISSUE. getBriefDescription (TextFormat. TEXT)); вернуть супер. visitEnumDeclaration (узел); }}

Поскольку у нас проверяется только один применимый тип узла, у нашего внутреннего класса есть только один переопределенный метод visitEnumDeclaration (...). Для каждого объявления Enum, обнаруженного при обходе AST, этот метод будет вызываться ровно один раз. Все, что он собирается сделать при вызове - сообщить о найденной проблеме.

Когда проблема найдена, мы используем метод report (...). Параметры метода: проблема, о которой сообщается, место, где проблема была обнаружена, и краткое описание проблемы. Существуют и другие версии метода отчета (...), в которых вы можете указать точные номера строк и предоставить более подробную информацию. Для наших целей простейший отчет отлично работает.

Наш детектор теперь может искать в файлах Java, идентифицировать узлы объявлений Enum, а затем кричать на нас, сообщая о каждом из этих экземпляров.

Отдельный реестр - это список всех проблем, о которых Lint должен заботиться из заданных правил JAR of Lint. По умолчанию Lint извлекает данные из одного реестра, класса с точно названным именем BuiltinIssueRegistry, в котором содержится более 200 различных проблем. Мы можем включить наш собственный EnumIssue в общий список Lint Issues, предоставив наш собственный Реестр. Реестр упакован в окончательный выходной файл JAR и будет указывать на все интересные новые проблемы, которые мы представили.

Код для пользовательского реестра расширяет абстрактный класс IssueRegistry и переопределяет один метод:

открытый класс CustomIssueRegistry расширяет IssueRegistry {закрытый список <Issue> mIssues = Arrays. asList (EnumDetector. ISSUE // Здесь можно полностью добавить больше); public CustomIssueRegistry () {} @Override public List <Issue> getIssues () {return mIssues; }}

Так как Реестр - это всего лишь ловушка для Lint, чтобы захватить все предоставленные Проблемы, здесь не так много волнения. Мы переопределяем метод getIssues (), чтобы Lint получил наш список, и мы также предоставляем пустой конструктор по умолчанию (который необходим), чтобы система могла легко создать наш новый Реестр.

Однако существует дополнительный шаг для нашего реестра. Мы должны внести некоторые изменения в наш файл build.gradle, где мы добавим некоторую информацию о выходном JAR, который будет собран:

jar {baseName 'com.bignerdranch.linette' версия '1.0' manifest {атрибуты 'Manifest-Version': атрибуты 1.0 ('Lint-Registry': 'com.bignerdranch.linette.registry.CustomIssueRegistry')}}

Для базового имени, версии и версии манифеста используйте имя пакета и версию, в которой вы находитесь. Важной частью является атрибут Lint-Registry, который должен быть полным путем нашего пользовательского реестра ошибок. Теперь манифест (то есть метаданные) нашего выходного JAR-файла будет содержать путь к нашему Реестру. Lint будет использовать этот путь для определения всех новых проблем, которые мы представляем.

Что касается реализации собственной проверки Lint, то мы закончили! Вот и все части: реализация, проблема, детектор и реестр. Однако, для простоты использования и правдивости, мы собираемся добавить несколько тестов, прежде чем расскажем, как создать JAR.

тестирование

Хотя тестирование на Android печально известно, тестирование Lint на удивление легко. Первое, что нам нужно сделать, это добавить несколько зависимостей в наш build.gradle:

Зависимости {testCompile 'junit: junit: 4.11' testCompile 'org.assertj: assertj-core: 3.0.0' testCompile 'org.mockito: mockito-core: 1.9.5' testCompile 'com.android.tools.lint: lint: 24.3.1 'testCompile' com.android.tools.lint: lint-tests: 24.3.1 'testCompile' com.android.tools:testutils:24.3.1 '}

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

sourceSets {main {java {srcDirs = ["lint / src / main / java"]}} test {java {srcDirs = ["lint / src / test / java"]}}}

С этими новыми дополнениями build.gradle мы можем начать тестирование.

Давайте начнем с чего-то простого, например, тестирования нашего нового реестра:

открытый класс CustomIssueRegistryTest {private CustomIssueRegistry mCustomIssueRegistry; / ** * Настройка для других методов тестирования * / @ Перед общедоступным void setUp () выдает Exception {mCustomIssueRegistry = new CustomIssueRegistry (); } / ** * Убедитесь, что реестр ошибок содержит правильное количество проблем * / @Test public void testNumberOfIssues () выдает исключение {int size = mCustomIssueRegistry. getIssues (). размер (); assertThat (размер). isEqualTo (1); } / ** * Проверьте, что реестр ошибок содержит корректные вопросы Issues * / @Test public void testGetIssues () выдает исключение {List <Issue> actual = mCustomIssueRegistry. getIssues (); assertThat (актуально). Содержит (EnumDetector. ВЫПУСК); }}

Мы просто создаем наш пользовательский реестр и проверяем его размер и список проблем на правильность. Там не так много, чтобы проверить здесь.

Тестирование детектора

Более интересные (и полезные) тесты для детектора. Эти тесты извлекут из внешних файлов примеров в вашем каталоге test-resources и выполнят проверку Lint для каждого из них. В моем примере кода на Github я абстрагировал часть этой логики в суперкласс для повторного использования. Вот сокращенная версия:

открытый класс EnumDetectorTest extends LintDetectorTest {приватная статическая конечная строка PATH_TEST_RESOURCES = "/ lint / src / test / resources / enum /"; private static final String NO_WARNINGS = "Нет предупреждений." ; @ Переопределить защищенный детектор getDetector () {return new EnumDetector (); } @ Переопределить защищенный список <Issue> getIssues () {return Arrays. asList (EnumDetector. ISSUE); } / ** * Проверьте, что пустой файл Java не имеет предупреждений. * / public void testEmptyCase () создает исключение {String file = "EmptyTestCase.java"; assertEquals (NO_WARNINGS, lintFiles (файл)); } / ** * Проверить, что в java-файле с перечислением есть предупреждение. * / public void testEnumCase () создает исключение {String file = "EnumTestCase.java"; String warningMessage = file + ": Warning:" + EnumDetector. ВЫПУСК. getBriefDescription (TextFormat. TEXT) + "[" + EnumDetector. ВЫПУСК. getId () + "] n" + "0 ошибок, 1 предупрежденийn"; assertEquals (warningMessage, lintFiles (file)); } @Override защищенный InputStream getTestResource (StringlativePath, логическое ожидание); {String path = (PATH_TEST_RESOURCES +lativePath). replace ('/', File. separatorChar); Файл файл = новый файл (getTestDataRootDir (), путь); if (file. exist ()) {try {return new BufferedInputStream (new FileInputStream (file)); } catch (FileNotFoundException e) {if (hopeExists) {fail («Не удалось найти файл» +lativePath); }}} return null; } приватный файл getTestDataRootDir () {CodeSource source = getClass (). getProtectionDomain (). getCodeSource (); if (source! = null) {URL location = source. getLocation (); попробуй {File classesDir = SdkUtils. urlToFile (местоположение); вернуть классыDir. getParentFile (). getAbsoluteFile (). getParentFile (). getParentFile (); } catch (MalformedURLException e) {fail (e. getLocalizedMessage ()); }} return null; }}

Уф! Это много кода, поэтому давайте разберем тестовый файл по частям, начав с двух методов установки:

@ Переопределить защищенный детектор getDetector () {return new EnumDetector (); } @ Переопределить защищенный список <Issue> getIssues () {return Arrays. asList (EnumDetector. ISSUE); }

Метод getDetector () предоставляет Детектор, который мы хотим протестировать, а метод getIssues () предоставляет Проблемы. Для них верните EnumDetector и EnumIssue соответственно.

Вот константы из верхней части файла:

приватная статическая final String PATH_TEST_RESOURCES = "/ lint / src / test / resources / enum /"; private static final String NO_WARNINGS = "Нет предупреждений." ;

Первая константа PATH_TEST_RESOURCES - это наш относительный путь к каталогу test-resources, который используется в методах getTestResource () и getTestDataRootDir (). Их цель - определить файл ресурса тестирования, который будет использоваться в данном тестовом примере. Вторая константа NO_WARNINGS - это сообщение Lint по умолчанию, когда все в порядке, что нам понадобится для сравнительных тестов.

Вот снова отдельные тесты:

public void testEmptyCase () создает исключение {String file = "EmptyTestCase.java"; assertEquals (NO_WARNINGS, lintFiles (файл)); } public void testEnumCase () throws Exception {String file = "EnumTestCase.java"; String warningMessage = file + ": Warning:" + EnumDetector. ВЫПУСК. getBriefDescription (TextFormat. TEXT) + "[" + EnumDetector. ВЫПУСК. getId () + "] n" + "0 ошибок, 1 предупрежденийn"; assertEquals (warningMessage, lintFiles (file)); }

У нас есть только два тестовых примера: пустой пример и небольшой пример Enum. Для каждого случая мы указываем на файл, который мы хотим проверить, а затем вызываем lintFiles (String path) на пути String. Если указанная выше директория test-resources правильно найдена, то вызов lintFiles () загрузит тестовый файл в память как проект Android на лету, а затем запустит проверку Lint, возвращая его вывод в виде значения String ,

Получив строку завершенной проверки Lint, мы сравниваем ее с ожидаемым. Для пустого тестового случая мы ожидаем значение, равное константе NO_WARNINGS. Для случая Enum мы ожидаем предупреждающее сообщение, которое состоит из множества различных переменных, которые мы определили в этом процессе. Выяснение того, каким будет фактическое предупреждающее сообщение, потребует некоторых проб и ошибок, но самая простая из проверок Lint (например, то, что мы сделали здесь) будет следовать шаблону конкатенации String, используемому в методе testEnumCase ().

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

Выполнение тестов

Мой любимый способ сделать что-нибудь через терминал. Перейдите в корень нашего пользовательского проекта проверки Lint и выполните следующую команду:

./gradlew тест чистой сборки

Ваш вывод должен выглядеть примерно так:

: clean: compileJava: processResources UP-TO-DATE: классы: jar: build: compileTestJava: processTestResources UP-TO-DATE: testClasses: test: check: build BUILD SUCCESSFUL Общее время: 6,373 с

Надеюсь, все хорошо. Я настоятельно рекомендую подход, основанный на тестировании, если вы начинаете создавать собственные проверки Lint. Это идеальный вариант использования - предоставьте образец файла, а затем напишите детектор или проблему в соответствии с ситуацией.

Линти Фреш

Если вы сделали это далеко, поздравляю. Ваша тяжелая работа скоро окупится. Если вы помните, конечный результат нашей специальной проверки Lint - это файл JAR. Каждый раз, когда мы хотим добавить проверки Lint в нашу систему, мы просто добавляем JAR-файл в наш каталог ~ / .android / lint /. Инструмент Lint всегда будет проверять наличие нового при каждом запуске. Запустив задачу сборки Gradle, мы будем генерировать и собирать JAR во время каждой сборки. Теперь мы можем переместить выходной JAR из нашего каталога сборки в каталог Lint вручную, но я предпочитаю включить его в процесс сборки, добавив эту удобную задачу Gradle в наш файл build.gradle:

defaultTasks задача «собрать» install (type: Copy) {из конфигураций. lintChecks в систему. getProperty ('user.home') + '/.android/lint/'}

Давайте создадим и установим нашу новую проверку Lint, запустив в терминале нашего пользовательского проекта проверки Lint следующую команду:

./gradlew чистая сборка тестовая установка

Предполагая, что все собирается и проходит, давайте проверим, доступно ли наше новое правило Lint:

lint - show Enum

Если все прошло гладко, вы должны увидеть следующее:

Enum ---- Описание: Избегайте использования Enums Приоритет: 5/10 Важность: Предупреждение Категория: Производительность Ни один настоящий программист Android никогда не должен использовать enum. КОГДА-ЛИБО.

Несмотря на то, что проверка Lint доступна на системном уровне - это замечательно, но в окончательной пробной версии мы фактически запускаем нашу новую проверку Lint для реального проекта, поэтому перейдите к реальному проекту приложения Android на ваш выбор и выполните следующее:

./gradlew lint

Вы также можете использовать опцию Android Studio Analyze-> Inspect Code ..., но это не интересно.

Предполагая, что все хорошо, результаты должны быть найдены в build / output / lint-results.html и выглядеть примерно так:

html и выглядеть примерно так:

Та-да! Наконец, наша система проверки Lint зарегистрирована в системе. Теперь мы можем использовать его в любом проекте. Это было настоящее путешествие: мы создали Реализацию, Проблему, Детектор, Реестр и несколько тестовых случаев, в дополнение к созданию магии Gradle. Lint - это недостаточно используемый инструмент для многих разработчиков Android, но я надеюсь, что теперь вы можете начать расширять границы и максимально использовать статический анализ кода.

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

Отдельное спасибо моему коллеге Джейсон Этвуд за всю его исследовательскую помощь и Андре Диерманн , Ежи Чалупски , а также Ченг Ян для того, чтобы я начал на правильном пути.

Похожие

Как превратить устройство Android в веб-сервер
Реклама Нужно маломощное устройство для запуска вашего сайта? Хотите освободить место, занимаемое вашим веб-сервером? Хотите поделиться информацией с людьми, друзьями или публикой, но у вас нет средств для запуска полнофункционального веб-сервера? Вы могли бы использовать эта ссылка на специальную скидку на хостинге InMotion. Или вы можете
NaviExpert - обзор навигационного приложения для Android => Tablety.pl
Предположим, вы являетесь владельцами таблетка
Сравнение инфраструктуры тестирования JavaScript: Жасмин против Мокко
(фото tdlucas5000 ) Тестирование на JavaScript становится все более и более ожидаемым разработчиками. Но с чего начать? Существует так много вариантов рамок. Это может быть довольно подавляющим. Этот пост представляет собой краткий обзор различий между двумя популярными средами тестирования JavaScript: Жасмин 2 а также
Использование пользовательских шрифтов в веб-дизайне
Типография является очень важным аспектом любой части дизайна. Всегда важно убедиться, что ваш текст разборчивый, читаемый и эстетически привлекательный при отображении. Однако в веб-дизайне ваши слова и предложения выглядят точно так же, как ваши оригинальные макеты и дизайны, часто может оказаться непростым делом, особенно если вы хотите использовать самые модные и модные шрифты. Веб Безопасные Шрифты Каждый раз, когда браузер загружает веб-страницу, в таблицах
7 из лучших каналов YouTube для изучения барабанов
Изучать барабаны сложно. подобно изучение любого музыкального инструмента Научитесь играть на музыкальном инструменте с помощью 7 бесплатных онлайн-уроков музыки Научитесь играть на музыкальном инструменте с
новости о том, что Facebook регистрирует звонки и тексты пользователей Android поднимает новые вопросы о политике конфид...
новости о том, что Facebook регистрирует звонки и тексты пользователей Android поднимает новые вопросы о политике конфиденциальности Facebook. Вот некоторые ответы и шаги для отказа. Facebook пояснил, что он просто хранит метаданные звонков, а не фактический контент. Но не заблуждайтесь: есть
Как проверить сайт WordPress в разных браузерах (простой способ)
Хотите протестировать свой сайт WordPress в разных браузерах? Кросс-браузерное тестирование чрезвычайно важно при изменении тем WordPress или реализации нового дизайна, поскольку оно помогает вам убедиться, что ваш сайт выглядит хорошо во всех браузерах, экранах, операционных системах и мобильных устройствах. В этой статье мы покажем вам, как легко тестировать сайт WordPress в разных браузерах.

Комментарии

Что такое кросс-браузерное тестирование?
Что такое кросс-браузерное тестирование? Кросс-браузерное тестирование - это процесс тестирования веб-сайтов в разных браузерах, операционных системах, размерах экрана и мобильных устройствах, чтобы убедиться, что ваш веб-сайт работает корректно во всех различных веб-браузерах. Зачем тестировать сайт WordPress в разных браузерах? Google Chrome - самый популярный веб-браузер в мире с долей рынка 65% на настольных компьютерах и 57% на мобильных устройствах. Однако
Как люди посещают страницы вашего веб-сервера Android?
Как люди посещают страницы вашего веб-сервера Android? Не имеет значения, размещаете ли вы свой сайт на смартфоне, планшете или даже на Android-телевизоре. Какое бы устройство Android вы не выбрали, при использовании вместе с клиент динамического обновления DNS 5 лучших провайдеров
Во всяком случае, это всегда была моя проблема: как украсить кухню?
Во всяком случае, это всегда была моя проблема: как украсить кухню? Хорошо, если я не знаю, какой стиль мне нравится. Однажды я очарован яркими, белыми минималистскими кухнями в скандинавском стиле, иногда я влюбляюсь, когда я вижу современные кухни, но в стиле кантри, и еще раз я мечтаю о кухне, полной красок, радости, оптимизма.
Проблема в том, что это не очень полезно для большинства людей - каковы шансы его найти?
Проблема в том, что это не очень полезно для большинства людей - каковы шансы его найти? Подумайте, сколько раз вы на самом деле используете кнопку «Мне повезет» от Google. Конкурирующие поисковые системы, как правило, отправляют запросы или опечатки в адресной строке непосредственно в поисковую систему по умолчанию. Это кажется более интуитивным подходом, чем случайное предположение на веб-сайте. Чтобы изменить стандартное поведение адресной строки Firefox, чтобы она использовала поисковую
Как вы проводите тестирование?
Как вы проводите тестирование? И что ты думаешь об этом? Как бы вы улучшили QA? Хороший код означает меньше глючных веб-приложений и меньше кризисов кодирования. Хороший веб-разработчик должен ценить тестирование и уважать процесс обеспечения качества, потому что он сократит количество поздних ночей, когда они пытаются найти проблему, которая была обнаружена в коде. Как вы идете в ногу с последними разработками в

Тип параметра Детектор - Класс <?
JAVA_FILE_SCOPE; } @Override public List <Class <?
Lt;Class <?
Lt;Class <?
Хотите освободить место, занимаемое вашим веб-сервером?
Хотите поделиться информацией с людьми, друзьями или публикой, но у вас нет средств для запуска полнофункционального веб-сервера?
Но с чего начать?
Что такое кросс-браузерное тестирование?
Зачем тестировать сайт WordPress в разных браузерах?
Как люди посещают страницы вашего веб-сервера Android?