From fe0058df5ff60f9a243d2d609af34d194a1690ce Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Tue, 18 Apr 2023 19:34:57 +0200 Subject: [PATCH 1/3] Ignore fields that are annotated with `@SpyBean` and `@MockBean` (Spring). --- gradle/dependencies.gradle | 1 + nullaway/build.gradle | 1 + .../nullaway/ErrorProneCLIFlagsConfig.java | 4 ++- .../uber/nullaway/NullAwayFrameworkTests.java | 35 +++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 528862b5fc..eba65fc416 100755 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -108,6 +108,7 @@ def test = [ lombok : "org.projectlombok:lombok:1.18.24", springBeans : "org.springframework:spring-beans:5.3.7", springContext : "org.springframework:spring-context:5.3.7", + springTest : "org.springframework.boot:spring-boot-test:2.7.5", grpcCore : "io.grpc:grpc-core:1.15.1", // Should upgrade, but this matches our guava version mockito : "org.mockito:mockito-core:4.6.1", mockitoInline : "org.mockito:mockito-inline:4.6.1", diff --git a/nullaway/build.gradle b/nullaway/build.gradle index 3b4f10f379..e2c978d96d 100644 --- a/nullaway/build.gradle +++ b/nullaway/build.gradle @@ -59,6 +59,7 @@ dependencies { testImplementation deps.test.lombok testImplementation deps.test.springBeans testImplementation deps.test.springContext + testImplementation deps.test.springTest testImplementation deps.test.grpcCore testImplementation project(":test-java-lib-lombok") testImplementation deps.test.mockito diff --git a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java index 939166a19a..d121e38725 100644 --- a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java +++ b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java @@ -151,7 +151,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 d3678632e8..1933280a67 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java @@ -262,6 +262,41 @@ public void springAutowiredFieldTest() { .doTest(); } + @Test + public void springTestAutowiredFieldTest() { + defaultCompilationHelper + .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 From 98ce0dd7a9d7426b96423034f1e7246170e20fa7 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Wed, 20 Sep 2023 09:51:53 +0200 Subject: [PATCH 2/3] Use stubs for the annotations `MockBean` and `SpyBean` in tests. This simplifies the tests: no dependency to spring boot is required. --- gradle/dependencies.gradle | 1 - nullaway/build.gradle | 1 - .../uber/nullaway/NullAwayFrameworkTests.java | 5 ++++- .../springboot-annotations/MockBean.java | 16 ++++++++++++++++ .../testdata/springboot-annotations/SpyBean.java | 15 +++++++++++++++ 5 files changed, 35 insertions(+), 3 deletions(-) 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/gradle/dependencies.gradle b/gradle/dependencies.gradle index eba65fc416..528862b5fc 100755 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -108,7 +108,6 @@ def test = [ lombok : "org.projectlombok:lombok:1.18.24", springBeans : "org.springframework:spring-beans:5.3.7", springContext : "org.springframework:spring-context:5.3.7", - springTest : "org.springframework.boot:spring-boot-test:2.7.5", grpcCore : "io.grpc:grpc-core:1.15.1", // Should upgrade, but this matches our guava version mockito : "org.mockito:mockito-core:4.6.1", mockitoInline : "org.mockito:mockito-inline:4.6.1", diff --git a/nullaway/build.gradle b/nullaway/build.gradle index e2c978d96d..3b4f10f379 100644 --- a/nullaway/build.gradle +++ b/nullaway/build.gradle @@ -59,7 +59,6 @@ dependencies { testImplementation deps.test.lombok testImplementation deps.test.springBeans testImplementation deps.test.springContext - testImplementation deps.test.springTest testImplementation deps.test.grpcCore testImplementation project(":test-java-lib-lombok") testImplementation deps.test.mockito diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java index 1933280a67..6104d95524 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java @@ -1,8 +1,9 @@ package com.uber.nullaway; -import java.util.Arrays; import org.junit.Test; +import java.util.Arrays; + public class NullAwayFrameworkTests extends NullAwayTestsBase { @Test public void lombokSupportTesting() { @@ -265,6 +266,8 @@ public void springAutowiredFieldTest() { @Test public void springTestAutowiredFieldTest() { defaultCompilationHelper + .addSourceFile("springboot-annotations/MockBean.java") + .addSourceFile("springboot-annotations/SpyBean.java") .addSourceLines( "Foo.java", "package com.uber;", 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..d100e8801b --- /dev/null +++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/MockBean.java @@ -0,0 +1,16 @@ +package org.springframework.boot.test.mock.mockito; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.mockito.Answers; +import org.springframework.core.annotation.AliasFor; + +@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..13d3bc9c55 --- /dev/null +++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/springboot-annotations/SpyBean.java @@ -0,0 +1,15 @@ +package org.springframework.boot.test.mock.mockito; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.core.annotation.AliasFor; + +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface SpyBean { +} From 48ce4e21cee4a3f9b28a1129b1f72c1a6268c7c3 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Wed, 20 Sep 2023 09:55:22 +0200 Subject: [PATCH 3/3] Cleanup imports. --- .../test/java/com/uber/nullaway/NullAwayFrameworkTests.java | 3 +-- .../nullaway/testdata/springboot-annotations/MockBean.java | 3 --- .../uber/nullaway/testdata/springboot-annotations/SpyBean.java | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java index 6104d95524..93fb62cdeb 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayFrameworkTests.java @@ -1,8 +1,7 @@ package com.uber.nullaway; -import org.junit.Test; - import java.util.Arrays; +import org.junit.Test; public class NullAwayFrameworkTests extends NullAwayTestsBase { @Test 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 index d100e8801b..9932938228 100644 --- 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 @@ -2,12 +2,9 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; -import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.mockito.Answers; -import org.springframework.core.annotation.AliasFor; @Target({ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) 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 index 13d3bc9c55..11a186a61a 100644 --- 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 @@ -2,11 +2,9 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; -import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.core.annotation.AliasFor; @Target({ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME)