Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@ dependencies {
testImplementation libs.androidx.core.testing
testImplementation libs.mockito.core
testImplementation libs.mockito.inline
testImplementation libs.robolectric
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.d4rk.androidtutorials.java.ads.managers;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.test.core.app.ApplicationProvider;

import com.d4rk.androidtutorials.java.R;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdLoader;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockedConstruction;
import org.robolectric.RobolectricTestRunner;

import java.util.concurrent.atomic.AtomicReference;

@RunWith(RobolectricTestRunner.class)
public class NativeAdLoaderTest {

@Test
public void loadSuccessAddsPopulatedViewAndRequestsLayout() {
Context context = ApplicationProvider.getApplicationContext();
TestContainer container = new TestContainer(context);
AdRequest adRequest = mock(AdRequest.class);

NativeAd nativeAd = mock(NativeAd.class);
when(nativeAd.getHeadline()).thenReturn("Headline");
when(nativeAd.getBody()).thenReturn("Body");
when(nativeAd.getCallToAction()).thenReturn("Install");
when(nativeAd.getAdvertiser()).thenReturn("Advertiser");

AtomicReference<NativeAd.OnNativeAdLoadedListener> listenerRef = new AtomicReference<>();

try (MockedConstruction<AdLoader.Builder> mocked = mockConstruction(AdLoader.Builder.class, (builder, ctx) -> {
when(builder.forNativeAd(any())).thenAnswer(inv -> {
listenerRef.set(inv.getArgument(0));
return builder;
});
when(builder.withAdListener(any())).thenReturn(builder);
AdLoader adLoader = mock(AdLoader.class);
when(builder.build()).thenReturn(adLoader);
doAnswer(inv -> {
listenerRef.get().onNativeAdLoaded(nativeAd);
return null;
}).when(adLoader).loadAd(any(AdRequest.class));
})) {
NativeAdLoader.load(context, container, R.layout.ad_home_banner_large, adRequest, null);
}
Comment on lines +37 to +65

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Enable Android resources for Robolectric tests

The new Robolectric tests call NativeAdLoader.load with R.layout.ad_home_banner_large (lines 37‑65) which inflates a real layout. Unit tests in this module currently run without packaged Android resources because android { testOptions.unitTests.includeAndroidResources = true } is not configured in app/build.gradle. With the default setting, Robolectric will throw Resources$NotFoundException when inflating the layout and the tests will never reach their assertions. Please turn on includeAndroidResources or move the tests to androidTest so resources are available.

Useful? React with 👍 / 👎.


assertEquals(1, container.getChildCount());
assertTrue(container.requestedLayout);
NativeAdView adView = (NativeAdView) container.getChildAt(0);
TextView headline = adView.findViewById(R.id.ad_headline);
assertEquals("Headline", headline.getText().toString());
Button cta = adView.findViewById(R.id.ad_call_to_action);
assertEquals("Install", cta.getText().toString());
}

@Test
public void loadFailureClearsContainerAndHides() {
Context context = ApplicationProvider.getApplicationContext();
TestContainer container = new TestContainer(context);
container.addView(new View(context));
AdRequest adRequest = mock(AdRequest.class);

AtomicReference<AdListener> listenerRef = new AtomicReference<>();

try (MockedConstruction<AdLoader.Builder> mocked = mockConstruction(AdLoader.Builder.class, (builder, ctx) -> {
when(builder.forNativeAd(any())).thenReturn(builder);
when(builder.withAdListener(any())).thenAnswer(inv -> {
listenerRef.set(inv.getArgument(0));
return builder;
});
AdLoader adLoader = mock(AdLoader.class);
when(builder.build()).thenReturn(adLoader);
doAnswer(inv -> {
listenerRef.get().onAdFailedToLoad(mock(LoadAdError.class));
return null;
}).when(adLoader).loadAd(any(AdRequest.class));
})) {
NativeAdLoader.load(context, container, R.layout.ad_home_banner_large, adRequest, null);
}

assertEquals(0, container.getChildCount());
assertEquals(View.GONE, container.getVisibility());
}

private static class TestContainer extends FrameLayout {
boolean requestedLayout = false;

TestContainer(Context context) {
super(context);
}

@Override
public void requestLayout() {
super.requestLayout();
requestedLayout = true;
}
}
}

2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ lifecycle = "2.9.3"
lottie = "6.6.7"
mockitoCore = "5.19.0"
mockitoInline = "5.2.0"
robolectric = "4.13.2"
navigationUi = "2.9.4"
preference = "1.2.1"
review = "2.0.2"
Expand Down Expand Up @@ -61,6 +62,7 @@ material = { module = "com.google.android.material:material", version.ref = "mat
materialratingbar-library = { module = "me.zhanghai.android.materialratingbar:library", version.ref = "libraryVersion" }
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" }
mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockitoInline" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
play-services-ads = { module = "com.google.android.gms:play-services-ads", version.ref = "playServicesAds" }
review = { module = "com.google.android.play:review", version.ref = "review" }
volley = { module = "com.android.volley:volley", version.ref = "volley" }
Expand Down
Loading