Skip to content

Commit 084fd5d

Browse files
Merge pull request #59 from MihaiCristianCondrea/codex/set-up-jvm-unit-tests-and-ci
Add repository and ViewModel unit tests
2 parents ed062b3 + 5d3662b commit 084fd5d

File tree

5 files changed

+182
-2
lines changed

5 files changed

+182
-2
lines changed

.github/workflows/android.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313

1414
steps:
1515
- uses: actions/checkout@v3
16-
- name: set up JDK 17
16+
- name: set up JDK 21
1717
uses: actions/setup-java@v3
1818
with:
19-
java-version: '17'
19+
java-version: '21'
2020
distribution: 'temurin'
2121
cache: gradle
2222

app/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,10 @@ dependencies {
9696
implementation libs.codeview
9797
implementation libs.hilt.android
9898
annotationProcessor libs.hilt.compiler
99+
100+
// Testing
101+
testImplementation 'junit:junit:4.13.2'
102+
testImplementation 'androidx.arch.core:core-testing:2.2.0'
103+
testImplementation 'org.mockito:mockito-core:5.12.0'
104+
testImplementation 'org.mockito:mockito-inline:5.2.0'
99105
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.d4rk.androidtutorials.java.data.repository;
2+
3+
import com.d4rk.androidtutorials.java.data.model.PromotedApp;
4+
import com.d4rk.androidtutorials.java.data.source.HomeLocalDataSource;
5+
import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource;
6+
7+
import org.junit.Test;
8+
9+
import java.util.List;
10+
11+
import static org.junit.Assert.*;
12+
13+
public class DefaultHomeRepositoryTest {
14+
15+
private static class FakeHomeLocalDataSource implements HomeLocalDataSource {
16+
@Override
17+
public String getPlayStoreUrl() {
18+
return "play";
19+
}
20+
21+
@Override
22+
public String getAppPlayStoreUrl(String packageName) {
23+
return "play/" + packageName;
24+
}
25+
26+
@Override
27+
public String getDailyTip() {
28+
return "tip";
29+
}
30+
}
31+
32+
private static class FakeHomeRemoteDataSource implements HomeRemoteDataSource {
33+
private final List<PromotedApp> apps;
34+
boolean called = false;
35+
36+
FakeHomeRemoteDataSource(List<PromotedApp> apps) {
37+
this.apps = apps;
38+
}
39+
40+
@Override
41+
public void fetchPromotedApps(PromotedAppsCallback callback) {
42+
called = true;
43+
callback.onResult(apps);
44+
}
45+
}
46+
47+
@Test
48+
public void repositoryDelegatesToDataSources() {
49+
List<PromotedApp> promoted = List.of(new PromotedApp("Name", "pkg", "icon"));
50+
FakeHomeRemoteDataSource remote = new FakeHomeRemoteDataSource(promoted);
51+
FakeHomeLocalDataSource local = new FakeHomeLocalDataSource();
52+
53+
DefaultHomeRepository repository = new DefaultHomeRepository(remote, local);
54+
55+
assertEquals("play", repository.getPlayStoreUrl());
56+
assertEquals("play/pkg", repository.getAppPlayStoreUrl("pkg"));
57+
assertEquals("tip", repository.getDailyTip());
58+
59+
final List<PromotedApp>[] result = new List[1];
60+
repository.fetchPromotedApps(apps -> result[0] = apps);
61+
assertTrue(remote.called);
62+
assertEquals(promoted, result[0]);
63+
}
64+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.d4rk.androidtutorials.java.data.repository;
2+
3+
import com.d4rk.androidtutorials.java.data.model.QuizQuestion;
4+
import com.d4rk.androidtutorials.java.data.source.QuizLocalDataSource;
5+
6+
import org.junit.Test;
7+
8+
import java.util.List;
9+
10+
import static org.junit.Assert.*;
11+
12+
public class DefaultQuizRepositoryTest {
13+
14+
private static class FakeQuizLocalDataSource implements QuizLocalDataSource {
15+
private final List<QuizQuestion> questions;
16+
17+
FakeQuizLocalDataSource(List<QuizQuestion> questions) {
18+
this.questions = questions;
19+
}
20+
21+
@Override
22+
public List<QuizQuestion> loadQuestions() {
23+
return questions;
24+
}
25+
}
26+
27+
@Test
28+
public void loadQuestionsReturnsLocalData() {
29+
List<QuizQuestion> expected = List.of(
30+
new QuizQuestion("Q", new String[]{"A", "B"}, 0)
31+
);
32+
FakeQuizLocalDataSource local = new FakeQuizLocalDataSource(expected);
33+
DefaultQuizRepository repository = new DefaultQuizRepository(local);
34+
assertEquals(expected, repository.loadQuestions());
35+
}
36+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.d4rk.androidtutorials.java.ui.screens.home;
2+
3+
import android.app.Application;
4+
5+
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
6+
7+
import com.d4rk.androidtutorials.java.R;
8+
import com.d4rk.androidtutorials.java.data.model.PromotedApp;
9+
import com.d4rk.androidtutorials.java.data.repository.HomeRepository;
10+
import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase;
11+
import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase;
12+
13+
import org.junit.Rule;
14+
import org.junit.Test;
15+
16+
import java.util.List;
17+
18+
import static org.junit.Assert.*;
19+
20+
import org.mockito.Mockito;
21+
22+
public class HomeViewModelTest {
23+
24+
@Rule
25+
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
26+
27+
28+
static class FakeHomeRepository implements HomeRepository {
29+
final String dailyTip;
30+
final List<PromotedApp> apps;
31+
32+
FakeHomeRepository(String dailyTip, List<PromotedApp> apps) {
33+
this.dailyTip = dailyTip;
34+
this.apps = apps;
35+
}
36+
37+
@Override public String getPlayStoreUrl() { return ""; }
38+
@Override public String getAppPlayStoreUrl(String packageName) { return ""; }
39+
@Override public String getDailyTip() { return dailyTip; }
40+
@Override public void fetchPromotedApps(PromotedAppsCallback callback) { callback.onResult(apps); }
41+
}
42+
43+
@Test
44+
public void uiStateUpdatesWithData() {
45+
List<PromotedApp> promoted = List.of(new PromotedApp("App", "pkg", "icon"));
46+
FakeHomeRepository repo = new FakeHomeRepository("tip", promoted);
47+
Application app = Mockito.mock(Application.class);
48+
Mockito.when(app.getString(R.string.announcement_title)).thenReturn("Title");
49+
Mockito.when(app.getString(R.string.announcement_subtitle)).thenReturn("Subtitle");
50+
HomeViewModel viewModel = new HomeViewModel(app, repo,
51+
new GetDailyTipUseCase(repo), new GetPromotedAppsUseCase(repo));
52+
53+
HomeUiState state = viewModel.getUiState().getValue();
54+
assertNotNull(state);
55+
assertEquals("Title", state.announcementTitle());
56+
assertEquals("Subtitle", state.announcementSubtitle());
57+
assertEquals("tip", state.dailyTip());
58+
assertEquals(promoted, state.promotedApps());
59+
}
60+
61+
@Test
62+
public void uiStateHandlesEmptyPromotedApps() {
63+
FakeHomeRepository repo = new FakeHomeRepository("tip", List.of());
64+
Application app = Mockito.mock(Application.class);
65+
Mockito.when(app.getString(R.string.announcement_title)).thenReturn("Title");
66+
Mockito.when(app.getString(R.string.announcement_subtitle)).thenReturn("Subtitle");
67+
HomeViewModel viewModel = new HomeViewModel(app, repo,
68+
new GetDailyTipUseCase(repo), new GetPromotedAppsUseCase(repo));
69+
70+
HomeUiState state = viewModel.getUiState().getValue();
71+
assertNotNull(state);
72+
assertTrue(state.promotedApps().isEmpty());
73+
}
74+
}

0 commit comments

Comments
 (0)