From ab387b9ec28411497bbff49711780128c3df1fe8 Mon Sep 17 00:00:00 2001 From: Ullrich Hafner Date: Wed, 20 Sep 2023 16:34:02 +0200 Subject: [PATCH] Ignore fields that are annotated with the `@MockBean` and `@SpyBean` annotations of Spring test (#757) This is a small followup to #477. When you are testing Spring (Boot) applications then you are replacing controllers that are normally injected via `@Autowired` with stubs, mocks or spies from Mockito. This is done with two similar annotations: - `@MockBean` - `@SpyBean` So it would be helpful if these are ignored as well. --- .../nullaway/ErrorProneCLIFlagsConfig.java | 4 +- .../uber/nullaway/NullAwayFrameworkTests.java | 37 +++++++++++++++++++ .../springboot-annotations/MockBean.java | 13 +++++++ .../springboot-annotations/SpyBean.java | 13 +++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/MockBean.java create mode 100644 nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/SpyBean.java diff --git a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java index 6e30e4e43f..9a189fe821 100644 --- a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java +++ b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java @@ -152,7 +152,9 @@ final class ErrorProneCLIFlagsConfig extends AbstractConfig { "javax.inject.Inject", // no explicit initialization when there is dependency injection "com.google.errorprone.annotations.concurrent.LazyInit", "org.checkerframework.checker.nullness.qual.MonotonicNonNull", - "org.springframework.beans.factory.annotation.Autowired"); + "org.springframework.beans.factory.annotation.Autowired", + "org.springframework.boot.test.mock.mockito.MockBean", + "org.springframework.boot.test.mock.mockito.SpyBean"); private static final String DEFAULT_URL = "http://t.uber.com/nullaway"; diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java index 33777eb641..ed62eccee9 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java @@ -262,6 +262,43 @@ public void springAutowiredFieldTest() { .doTest(); } + @Test + public void springTestAutowiredFieldTest() { + defaultCompilationHelper + .addSourceFile("springboot-annotations/MockBean.java") + .addSourceFile("springboot-annotations/SpyBean.java") + .addSourceLines( + "Foo.java", + "package com.uber;", + "import javax.annotation.Nullable;", + "import org.springframework.stereotype.Component;", + "@Component", + "public class Foo {", + " @Nullable String bar;", + " public void setBar(String s) {", + " bar = s;", + " }", + "}") + .addSourceLines( + "TestCase.java", + "package com.uber;", + "import org.junit.jupiter.api.Test;", + "import org.springframework.boot.test.mock.mockito.SpyBean;", + "import org.springframework.boot.test.mock.mockito.MockBean;", + "public class TestCase {", + " @SpyBean", + " private Foo spy;", // Initialized by spring test (via Mockito). + " @MockBean", + " private Foo mock;", // Initialized by spring test (via Mockito). + " @Test", + " void springTest() {", + " spy.setBar(\"hello\");", + " mock.setBar(\"hello\");", + " }", + "}") + .doTest(); + } + @Test public void springAutowiredConstructorTest() { defaultCompilationHelper diff --git a/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/MockBean.java b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/MockBean.java new file mode 100644 index 0000000000..9932938228 --- /dev/null +++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/MockBean.java @@ -0,0 +1,13 @@ +package org.springframework.boot.test.mock.mockito; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MockBean { +} diff --git a/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/SpyBean.java b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/SpyBean.java new file mode 100644 index 0000000000..11a186a61a --- /dev/null +++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/SpyBean.java @@ -0,0 +1,13 @@ +package org.springframework.boot.test.mock.mockito; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface SpyBean { +}