Улучшите проверку кода с помощью аннотаций

Использование инструментов проверки кода, таких как lint , может помочь вам найти проблемы и улучшить ваш код, но инструменты проверки могут сделать лишь ограниченное заключение. Например, идентификаторы ресурсов Android используют int для идентификации строк, графики, цветов и других типов ресурсов, поэтому инструменты проверки не могут определить, когда вы указали строковый ресурс там, где вы должны были указать цвет. Такая ситуация означает, что ваше приложение может отображаться неправильно или вообще не запускаться, даже если вы используете проверку кода.

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

Android поддерживает множество аннотаций через Jetpack Annotations Library . Вы можете получить доступ к библиотеке через пакет androidx.annotation .

Примечание: Если модуль имеет зависимость от процессора аннотаций, необходимо использовать конфигурацию зависимости kapt или ksp для Kotlin или конфигурацию зависимости annotationProcessor для Java, чтобы добавить эту зависимость.

Добавьте аннотации к вашему проекту

Чтобы включить аннотации в вашем проекте, добавьте зависимость androidx.annotation:annotation в вашу библиотеку или приложение. Любые добавленные вами аннотации проверяются при запуске задачи проверки кода или lint .

Добавьте зависимость библиотеки аннотаций Jetpack

Библиотека аннотаций Jetpack опубликована в репозитории Maven от Google . Чтобы добавить библиотеку аннотаций Jetpack в свой проект, включите следующую строку в блок dependencies вашего файла build.gradle или build.gradle.kts :

Котлин

dependencies {
    implementation("androidx.annotation:annotation:1.9.1")
}

Круто

dependencies {
    implementation 'androidx.annotation:annotation:1.9.1'
}
Затем на панели инструментов или в появившемся уведомлении о синхронизации нажмите «Синхронизировать сейчас» .

Если вы используете аннотации в своем собственном модуле библиотеки, аннотации включаются как часть артефакта Android Archive (AAR) в формате XML в файле annotations.zip . Добавление зависимости androidx.annotation не вводит зависимость для каких-либо нижестоящих пользователей вашей библиотеки.

Примечание: Если вы используете другие библиотеки Jetpack, вам может не понадобиться добавлять зависимость androidx.annotation . Поскольку многие другие библиотеки Jetpack зависят от библиотеки аннотаций, у вас может уже быть доступ к аннотациям.

Полный список аннотаций, включенных в репозиторий Jetpack, можно найти в справочнике по библиотеке аннотаций Jetpack или воспользоваться функцией автозаполнения, чтобы отобразить доступные параметры для оператора import androidx.annotation.

Проведение проверок кода

Чтобы запустить проверку кода из Android Studio, которая включает проверку аннотаций и автоматическую проверку линта, выберите в меню Анализ > Проверка кода . Android Studio отображает сообщения о конфликтах, чтобы отметить потенциальные проблемы, в которых ваш код конфликтует с аннотациями, и предложить возможные решения.

Вы также можете принудительно применять аннотации, запустив задачу lint с помощью командной строки . Хотя это может быть полезно для выявления проблем с сервером непрерывной интеграции, задача lint не применяет аннотации nullness (описанные в следующем разделе); это делает только Android Studio. Для получения дополнительной информации о включении и запуске проверок lint см. раздел Улучшение кода с помощью проверок lint .

Хотя конфликты аннотаций приводят к появлению предупреждений, эти предупреждения не мешают компиляции вашего приложения.

Аннотации об отсутствии

Аннотации nullness могут быть полезны в коде Java для обеспечения того, могут ли значения быть null. Они менее полезны в коде Kotlin, поскольку в Kotlin есть встроенные правила nullability, которые применяются во время компиляции.

Добавьте аннотации @Nullable и @NonNull , чтобы проверить нулевое значение заданной переменной, параметра или возвращаемого значения. Аннотация @Nullable указывает на переменную, параметр или возвращаемое значение, которые могут быть нулевыми. @NonNull указывает на переменную, параметр или возвращаемое значение, которые не могут быть нулевыми.

Например, если локальная переменная, содержащая значение null, передается в качестве параметра методу с аннотацией @NonNull , прикрепленной к этому параметру, сборка кода генерирует предупреждение, указывающее на конфликт ненулевых значений. Кроме того, попытка сослаться на результат метода, помеченного @Nullable , без предварительной проверки того, является ли результат null, генерирует предупреждение о ненулевости. Используйте @Nullable для возвращаемого значения метода только в том случае, если каждое использование метода должно явно проверяться на null.

Следующий пример демонстрирует возможность null в действии. Пример кода Kotlin не использует аннотацию @NonNull , поскольку она автоматически добавляется в сгенерированный байт-код, когда указан не допускающий null тип. Пример Java использует аннотацию @NonNull в параметрах context и attrs для проверки того, что переданные значения параметров не равны null. Он также проверяет, что сам метод onCreateView() не возвращает null:

Котлин

...
    /** Annotation not used because of the safe-call operator(?)**/
    override fun onCreateView(
            name: String?,
            context: Context,
            attrs: AttributeSet
    ): View? {
        ...
    }
...

Ява

import androidx.annotation.NonNull;
...
    /** Add support for inflating the <fragment> tag. **/
    @NonNull
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {
      ...
      }
...

Анализ недействительности

Android Studio поддерживает запуск анализа nullability для автоматического вывода и вставки аннотаций nullability в ваш код. Анализ nullability сканирует контракты по всей иерархии методов в вашем коде для обнаружения:

  • Вызов методов, которые могут возвращать значение null.
  • Методы, которые не должны возвращать значение null.
  • Переменные, такие как поля, локальные переменные и параметры, которые могут быть нулевыми.
  • Переменные, такие как поля, локальные переменные и параметры, которые не могут содержать нулевое значение.

Затем анализ автоматически вставляет соответствующие нулевые аннотации в обнаруженные места.

Чтобы запустить анализ на допустимость значений null в Android Studio, выберите Analyze > Infer Nullity . Android Studio вставляет аннотации Android @Nullable и @NonNull в обнаруженные места в вашем коде. После запуска анализа на допустимость значений null рекомендуется проверить внедренные аннотации.

Примечание: при добавлении аннотаций nullness функция автозаполнения может предложить аннотации IntelliJ @Nullable и @NotNull вместо аннотаций Android null и может автоматически импортировать соответствующую библиотеку. Однако средство проверки lint в Android Studio ищет только аннотации Android null. При проверке аннотаций убедитесь, что ваш проект использует аннотации Android null, чтобы средство проверки lint могло правильно уведомить вас во время проверки кода.

Аннотации ресурсов

Проверка типов ресурсов может быть полезна, поскольку ссылки Android на ресурсы, такие как ресурсы рисования и строковые ресурсы, передаются как целые числа.

Код, который ожидает, что параметр будет ссылаться на определенный тип ресурса, например, String , может быть передан ожидаемому ссылочному типу int , но фактически ссылаться на другой тип ресурса, например, на ресурс R.string .

Например, добавьте аннотации @StringRes , чтобы проверить, содержит ли параметр ресурса ссылку R.string , как показано здесь:

Котлин

abstract fun setTitle(@StringRes resId: Int)

Ява

public abstract void setTitle(@StringRes int resId)

Во время проверки кода аннотация генерирует предупреждение, если в параметре не передана ссылка на R.string .

Аннотации для других типов ресурсов, таких как @DrawableRes , @DimenRes , @ColorRes и @InterpolatorRes , можно добавлять с использованием того же формата аннотаций и запускать во время проверки кода.

Если ваш параметр поддерживает несколько типов ресурсов, вы можете поместить более одной аннотации типа ресурса на заданный параметр. Используйте @AnyRes , чтобы указать, что аннотированный параметр может быть любым типом ресурса R

Хотя вы можете использовать @ColorRes для указания того, что параметр должен быть цветовым ресурсом, целое число цвета (в формате RRGGBB или AARRGGBB ) не распознается как цветовой ресурс. Вместо этого используйте аннотацию @ColorInt для указания того, что параметр должен быть целым числом цвета. Инструменты сборки будут отмечать неверный код, который передает идентификатор цветового ресурса, такой как android.R.color.black , а не целое число цвета, в аннотированные методы.

Аннотации к темам

Аннотации потоков проверяют, вызывается ли метод из определенного типа потока . Поддерживаются следующие аннотации потоков:

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

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

Распространенным применением аннотаций потоков является проверка того, что методы или классы, аннотированные @WorkerThread , вызываются только из соответствующего фонового потока.

Аннотации ограничений значений

Используйте аннотации @IntRange , @FloatRange и @Size для проверки значений переданных параметров. Оба @IntRange и @FloatRange наиболее полезны при применении к параметрам, где пользователи, скорее всего, неправильно определят диапазон.

Аннотация @IntRange проверяет, что целочисленное или длинное значение параметра находится в указанном диапазоне. Следующий пример показывает, что параметр alpha должен содержать целочисленное значение от 0 до 255:

Котлин

fun setAlpha(@IntRange(from = 0, to = 255) alpha: Int) { ... }

Ява

public void setAlpha(@IntRange(from=0,to=255) int alpha) { ... }

Аннотация @FloatRange проверяет, находится ли значение параметра float или double в указанном диапазоне значений с плавающей точкой. Следующий пример показывает, что параметр alpha должен содержать значение float от 0,0 до 1,0:

Котлин

fun setAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float) {...}

Ява

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

Аннотация @Size проверяет размер коллекции или массива или длину строки. Аннотация @Size может использоваться для проверки следующих качеств:

  • Минимальный размер, например @Size(min=2)
  • Максимальный размер, например @Size(max=2)
  • Точный размер, например @Size(2)
  • Число, которому должен быть кратен размер, например @Size(multiple=2)

Например, @Size(min=1) проверяет, не является ли коллекция пустой, а @Size(3) проверяет, что массив содержит ровно три значения.

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

Котлин

fun getLocation(button: View, @Size(min=1) location: IntArray) {
    button.getLocationOnScreen(location)
}

Ява

void getLocation(View button, @Size(min=1) int[] location) {
    button.getLocationOnScreen(location);
}

Аннотации разрешений

Используйте аннотацию @RequiresPermission для проверки разрешений вызывающей стороны метода. Чтобы проверить одно разрешение из списка допустимых разрешений, используйте атрибут anyOf . Чтобы проверить набор разрешений, используйте атрибут allOf . Следующий пример аннотирует метод setWallpaper() , чтобы указать, что вызывающая сторона метода должна иметь permission.SET_WALLPAPERS permission.SET_WALLPAPERS:

Котлин

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
@Throws(IOException::class)
abstract fun setWallpaper(bitmap: Bitmap)

Ява

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;

В следующем примере требуется, чтобы вызывающая сторона метода copyImageFile() имела как доступ на чтение к внешнему хранилищу, так и доступ на чтение к метаданным местоположения в скопированном изображении:

Котлин

@RequiresPermission(allOf = [
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION
])
fun copyImageFile(dest: String, source: String) {
    ...
}

Ява

@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.ACCESS_MEDIA_LOCATION})
public static final void copyImageFile(String dest, String source) {
    //...
}

Для разрешений на намерения поместите требование разрешения в строковое поле, которое определяет имя действия намерения:

Котлин

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
const val ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"

Ява

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

Для разрешений для поставщиков контента, которым требуются отдельные разрешения для доступа к чтению и записи, заключите каждое требование к разрешению в аннотацию @RequiresPermission.Read или @RequiresPermission.Write :

Котлин

@RequiresPermission.Read(RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(RequiresPermission(WRITE_HISTORY_BOOKMARKS))
val BOOKMARKS_URI = Uri.parse("content://browser/bookmarks")

Ява

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");

Косвенные разрешения

Когда разрешение зависит от конкретного значения, предоставленного параметру метода, используйте @RequiresPermission для самого параметра, не перечисляя конкретные разрешения. Например, метод startActivity(Intent) использует косвенное разрешение на намерение, переданное методу:

Котлин

abstract fun startActivity(@RequiresPermission intent: Intent, bundle: Bundle?)

Ява

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle)

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

Рисунок 1. Предупреждение, сгенерированное из косвенной аннотации разрешений в методе startActivity(Intent) .

Инструменты сборки генерируют предупреждение о startActivity(Intent) из аннотации к соответствующему имени действия намерения в классе Intent :

Котлин

@RequiresPermission(Manifest.permission.CALL_PHONE)
const val ACTION_CALL = "android.intent.action.CALL"

Ява

@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

При необходимости вы можете заменить @RequiresPermission на @RequiresPermission.Read или @RequiresPermission.Write при аннотировании параметра метода. Однако для косвенных разрешений @RequiresPermission не следует использовать вместе с аннотациями разрешений на чтение или запись.

Аннотации возвращаемого значения

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

Например, новые разработчики Java часто ошибочно думают, что < String >.trim() удаляет пробелы из исходной строки. Аннотирование метода с помощью @CheckResult помечает использование < String >.trim() , когда вызывающий ничего не делает с возвращаемым значением метода.

Следующий пример аннотирует метод checkPermissions() для проверки того, ссылается ли на него возвращаемое значение метода. Он также называет метод enforcePermission() как метод, который следует предложить разработчику в качестве замены:

Котлин

@CheckResult(suggest = "#enforcePermission(String,int,int,String)")
abstract fun checkPermission(permission: String, pid: Int, uid: Int): Int

Ява

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

Аннотации CallSuper

Используйте аннотацию @CallSuper для проверки того, что переопределяющий метод вызывает суперреализацию метода.

В следующем примере аннотируется метод onCreate() чтобы гарантировать, что любые переопределяющие реализации метода вызывают super.onCreate() :

Котлин

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
}

Ява

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

Аннотации Typedef

Аннотации typedef проверяют, ссылается ли конкретный параметр, возвращаемое значение или поле на определенный набор констант. Они также позволяют автодополнению кода автоматически предлагать разрешенные константы.

Используйте аннотации @IntDef и @StringDef для создания перечислимых аннотаций целочисленных и строковых наборов для проверки других типов ссылок на код.

Аннотации Typedef используют @interface для объявления нового типа перечисляемой аннотации. Аннотации @IntDef и @StringDef вместе с @Retention аннотируют новую аннотацию и необходимы для определения перечисляемого типа. Аннотация @Retention(RetentionPolicy.SOURCE) сообщает компилятору, что не следует сохранять данные перечисляемой аннотации в файле .class .

В следующем примере показаны шаги по созданию аннотации, которая проверяет, ссылается ли значение, переданное в качестве параметра метода, на одну из определенных констант:

Котлин

import androidx.annotation.IntDef
//...
// Define the list of accepted constants and declare the NavigationMode annotation.
@Retention(AnnotationRetention.SOURCE)
@IntDef(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS)
annotation class NavigationMode

// Declare the constants.
const val NAVIGATION_MODE_STANDARD = 0
const val NAVIGATION_MODE_LIST = 1
const val NAVIGATION_MODE_TABS = 2

abstract class ActionBar {

    // Decorate the target methods with the annotation.
    // Attach the annotation.
    @get:NavigationMode
    @setparam:NavigationMode
    abstract var navigationMode: Int

}

Ява

import androidx.annotation.IntDef;
//...
public abstract class ActionBar {
    //...
    // Define the list of accepted constants and declare the NavigationMode annotation.
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    public @interface NavigationMode {}

    // Declare the constants.
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    // Decorate the target methods with the annotation.
    @NavigationMode
    public abstract int getNavigationMode();

    // Attach the annotation.
    public abstract void setNavigationMode(@NavigationMode int mode);
}

При сборке этого кода выдается предупреждение, если параметр mode не ссылается на одну из определенных констант ( NAVIGATION_MODE_STANDARD , NAVIGATION_MODE_LIST или NAVIGATION_MODE_TABS ).

Объедините @IntDef и @IntRange чтобы указать, что целое число может быть либо заданным набором констант, либо значением в пределах диапазона.

Включить объединение констант с флагами

Если пользователи могут комбинировать разрешенные константы с флагом (например | , & , ^ и т. д.), вы можете определить аннотацию с атрибутом flag , чтобы проверить, ссылается ли параметр или возвращаемое значение на допустимый шаблон.

В следующем примере создается аннотация DisplayOptions со списком допустимых констант DISPLAY_ :

Котлин

import androidx.annotation.IntDef
...

@IntDef(flag = true, value = [
    DISPLAY_USE_LOGO,
    DISPLAY_SHOW_HOME,
    DISPLAY_HOME_AS_UP,
    DISPLAY_SHOW_TITLE,
    DISPLAY_SHOW_CUSTOM
])
@Retention(AnnotationRetention.SOURCE)
annotation class DisplayOptions
...

Ява

import androidx.annotation.IntDef;
...

@IntDef(flag=true, value={
        DISPLAY_USE_LOGO,
        DISPLAY_SHOW_HOME,
        DISPLAY_HOME_AS_UP,
        DISPLAY_SHOW_TITLE,
        DISPLAY_SHOW_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayOptions {}

...

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

Сохранить аннотацию

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

Внимание: классы и методы, которые вы аннотируете с помощью @Keep всегда отображаются в APK вашего приложения, даже если вы никогда не ссылаетесь на эти классы и методы в логике вашего приложения.

Чтобы сохранить небольшой размер вашего приложения, подумайте, необходимо ли сохранять каждую аннотацию @Keep в вашем приложении. Если вы используете рефлексию для доступа к аннотированному классу или методу, используйте условие -if в правилах ProGuard, указав класс, который выполняет вызовы рефлексии.

Дополнительную информацию о том, как минимизировать код и указать, какой код не следует удалять, см . в разделе Сжатие, обфускация и оптимизация вашего приложения .

Аннотации видимости кода

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

Сделайте код видимым для тестирования

Аннотация @VisibleForTesting указывает, что аннотированный метод более видим, чем обычно необходимо для того, чтобы сделать метод тестируемым. Эта аннотация имеет необязательный аргумент otherwise , который позволяет вам указать, какой была бы видимость метода, если бы не было необходимости делать его видимым для тестирования. Lint использует аргумент otherwise для обеспечения предполагаемой видимости.

В следующем примере myMethod() обычно является private , но для тестов он является package-private . С обозначением VisibleForTesting.PRIVATE lint отображает сообщение, если этот метод вызывается извне контекста, разрешенного private доступом, например из другого модуля компиляции.

Котлин

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun myMethod() {
    ...
}

Ява

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
void myMethod() { ... }

Вы также можете указать @VisibleForTesting(otherwise = VisibleForTesting.NONE) чтобы указать, что метод существует только для тестирования. Эта форма такая же, как и при использовании @RestrictTo(TESTS) . Они оба выполняют одну и ту же проверку lint.

Ограничить API

Аннотация @RestrictTo указывает, что доступ к аннотированному API (пакету, классу или методу) ограничен следующим образом:

Подклассы

Используйте форму аннотации @RestrictTo(RestrictTo.Scope.SUBCLASSES) , чтобы ограничить доступ API только подклассами.

Только классы, расширяющие аннотированный класс, могут получить доступ к этому API. Модификатор Java protected недостаточно ограничителен, поскольку он разрешает доступ из не связанных классов в том же пакете. Кроме того, бывают случаи, когда вы хотите оставить метод public для будущей гибкости, поскольку вы никогда не сможете сделать ранее protected и переопределенный метод public , но вы хотите указать, что класс предназначен для использования только внутри класса или из подклассов.

Библиотеки

Используйте форму аннотации @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) чтобы ограничить доступ API только вашими библиотеками.

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

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

Используйте форму аннотации @RestrictTo(RestrictTo.Scope.TESTS) чтобы запретить другим разработчикам доступ к вашим API тестирования.

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