Permalink
Browse files

Dynamic parameters in use cases.

  • Loading branch information...
android10 committed Dec 23, 2016
1 parent 988e02b commit dfd61c29170b74298780ebb7cc991e0b2edbdfe6
Showing with 233 additions and 69 deletions.
  1. +4 −1 buildsystem/dependencies.gradle
  2. +3 −1 domain/build.gradle
  3. +15 −6 domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java
  4. +2 −1 domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
  5. +50 −0 domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/Params.java
  6. +9 −8 domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java
  7. +3 −4 domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java
  8. +31 −5 domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java
  9. +14 −1 domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java
  10. +49 −0 domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/ParamsTest.java
  11. +10 −12 domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java
  12. +5 −2 .../androidTest/java/com/fernandocejas/android10/sample/test/presenter/UserDetailsPresenterTest.java
  13. +2 −1 ...src/androidTest/java/com/fernandocejas/android10/sample/test/presenter/UserListPresenterTest.java
  14. +1 −7 ...src/main/java/com/fernandocejas/android10/sample/presentation/internal/di/modules/UserModule.java
  15. +11 −14 ...src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java
  16. +2 −1 ...on/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java
  17. +1 −3 .../main/java/com/fernandocejas/android10/sample/presentation/view/activity/UserDetailsActivity.java
  18. +21 −2 .../main/java/com/fernandocejas/android10/sample/presentation/view/fragment/UserDetailsFragment.java
@@ -22,6 +22,7 @@ ext {
gsonVersion = '2.3'
okHttpVersion = '2.5.0'
androidAnnotationsVersion = '21.0.3'
arrowVersion = '1.0.0'
//Testing
robolectricVersion = '3.1.1'
@@ -42,7 +43,7 @@ ext {
recyclerView: "com.android.support:recyclerview-v7:${recyclerViewVersion}",
rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}",
javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}"
]
presentationTestDependencies = [
@@ -57,11 +58,13 @@ ext {
javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
javaxInject: "javax.inject:javax.inject:${javaxInjectVersion}",
rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
arrow: "com.fernandocejas:arrow:${arrowVersion}"
]
domainTestDependencies = [
junit: "junit:junit:${jUnitVersion}",
mockito: "org.mockito:mockito-core:${mockitoVersion}",
assertj: "org.assertj:assertj-core:${assertJVersion}"
]
dataDependencies = [
@@ -23,7 +23,9 @@ dependencies {
compile domainDependencies.javaxInject
compile domainDependencies.rxJava
compile domainDependencies.arrow
testCompile domainTestDependencies.junit
testCompile domainTestDependencies.mockito
}
testCompile domainTestDependencies.assertj
}
@@ -19,6 +19,8 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.arrow.annotations.VisibleForTesting;
import com.fernandocejas.arrow.optional.Optional;
import javax.inject.Inject;
import rx.Observable;
@@ -29,19 +31,26 @@
public class GetUserDetails extends UseCase {
public static final String NAME = "userDetails";
public static final String PARAM_USER_ID_KEY = "userId";
@VisibleForTesting
static final int PARAM_USER_ID_DEFAULT_VALUE = -1;
private final int userId;
private final UserRepository userRepository;
@Inject
public GetUserDetails(int userId, UserRepository userRepository,
ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
public GetUserDetails(UserRepository userRepository, ThreadExecutor threadExecutor,
PostExecutionThread postExecutionThread) {
super(threadExecutor, postExecutionThread);
this.userId = userId;
this.userRepository = userRepository;
}
@Override protected Observable buildUseCaseObservable() {
return this.userRepository.user(this.userId);
@Override protected Observable buildUseCaseObservable(Optional<Params> params) {
if (params.isPresent()) {
final int userId = params.get().getInt(PARAM_USER_ID_KEY, PARAM_USER_ID_DEFAULT_VALUE);
return this.userRepository.user(userId);
} else {
return Observable.empty();
}
}
}
@@ -19,6 +19,7 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.arrow.optional.Optional;
import javax.inject.Inject;
import rx.Observable;
@@ -39,7 +40,7 @@
this.userRepository = userRepository;
}
@Override public Observable buildUseCaseObservable() {
@Override public Observable buildUseCaseObservable(Optional<Params> params) {
return this.userRepository.users();
}
}
@@ -0,0 +1,50 @@
/**
* Copyright (C) 2016 Fernando Cejas Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fernandocejas.android10.sample.domain.interactor;
import java.util.HashMap;
import java.util.Map;
/**
* Class backed by a Map, used to pass parameters to {@link UseCase} instances.
*/
public final class Params {
public static final Params EMPTY = Params.create();

This comment has been minimized.

@eduardb

eduardb Dec 25, 2016

Shouldn't this be an immutable object, so others won't be able to add elements into it? (Similar to how Collections.EMPTY_MAP is)

private final Map<String, Object> parameters = new HashMap<>();
private Params() {}
public static Params create() {
return new Params();
}
public void putInt(String key, int value) {
parameters.put(key, value);
}
int getInt(String key, int defaultValue) {
final Object object = parameters.get(key);
if (object == null) {
return defaultValue;
}
try {
return (int) object;
} catch (ClassCastException e) {
return defaultValue;
}
}
}
@@ -17,8 +17,9 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import rx.Subscriber;
import com.fernandocejas.arrow.optional.Optional;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;
@@ -38,26 +39,26 @@
private Subscription subscription = Subscriptions.empty();
protected UseCase(ThreadExecutor threadExecutor,
PostExecutionThread postExecutionThread) {
protected UseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
this.threadExecutor = threadExecutor;
this.postExecutionThread = postExecutionThread;
}
/**
* Builds an {@link rx.Observable} which will be used when executing the current {@link UseCase}.
*/
protected abstract Observable buildUseCaseObservable();
protected abstract Observable buildUseCaseObservable(Optional<Params> params);
/**
* Executes the current use case.
*
* @param useCaseSubscriber The guy who will be listen to the observable build
* with {@link #buildUseCaseObservable()}.
* @param useCaseSubscriber Subscriber which will be listening to the observable build
* by {@link #buildUseCaseObservable(Optional)} ()} method.
* @param params Parameters used to build execute this use case.
*/
@SuppressWarnings("unchecked")
public void execute(Subscriber useCaseSubscriber) {
this.subscription = this.buildUseCaseObservable()
public void execute(Subscriber useCaseSubscriber, Params params) {
this.subscription = this.buildUseCaseObservable(Optional.of(params))
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(useCaseSubscriber);
@@ -18,8 +18,7 @@
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
public class UserTest {
@@ -34,8 +33,8 @@ public void setUp() {
@Test
public void testUserConstructorHappyCase() {
int userId = user.getUserId();
final int userId = user.getUserId();
assertThat(userId, is(FAKE_USER_ID));
assertThat(userId).isEqualTo(FAKE_USER_ID);
}
}
@@ -18,20 +18,23 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.arrow.optional.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import rx.Observable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@RunWith(MockitoJUnitRunner.class)
public class GetUserDetailsTest {
private static final int FAKE_USER_ID = 123;
private static final int USER_ID = 123;
private GetUserDetails getUserDetails;
@@ -41,15 +44,38 @@
@Before
public void setUp() {
getUserDetails = new GetUserDetails(FAKE_USER_ID, mockUserRepository,
mockThreadExecutor, mockPostExecutionThread);
getUserDetails = new GetUserDetails(mockUserRepository, mockThreadExecutor,
mockPostExecutionThread);
}
@Test
public void testGetUserDetailsUseCaseObservableHappyCase() {
getUserDetails.buildUseCaseObservable();
final Params params = Params.create();
params.putInt(GetUserDetails.PARAM_USER_ID_KEY, USER_ID);
verify(mockUserRepository).user(FAKE_USER_ID);
getUserDetails.buildUseCaseObservable(Optional.of(params));
verify(mockUserRepository).user(USER_ID);
verifyNoMoreInteractions(mockUserRepository);
verifyZeroInteractions(mockPostExecutionThread);
verifyZeroInteractions(mockThreadExecutor);
}
@Test
public void testShouldReturnEmptyObservableWhenNoParameters() {
final Observable observable = getUserDetails.buildUseCaseObservable(Optional.<Params>absent());
assertThat(observable).isEqualTo(Observable.empty());
verifyZeroInteractions(mockUserRepository);
verifyZeroInteractions(mockPostExecutionThread);
verifyZeroInteractions(mockThreadExecutor);
}
@Test
public void testShouldUseDefaultUserIdValueWhenNoUserIdParameter() {
getUserDetails.buildUseCaseObservable(Optional.of(Params.create()));
verify(mockUserRepository).user(GetUserDetails.PARAM_USER_ID_DEFAULT_VALUE);
verifyNoMoreInteractions(mockUserRepository);
verifyZeroInteractions(mockPostExecutionThread);
verifyZeroInteractions(mockThreadExecutor);
@@ -18,12 +18,14 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.arrow.optional.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -45,11 +47,22 @@ public void setUp() {
@Test
public void testGetUserListUseCaseObservableHappyCase() {
getUserList.buildUseCaseObservable();
getUserList.buildUseCaseObservable(Optional.of(Params.EMPTY));
verify(mockUserRepository).users();
verifyNoMoreInteractions(mockUserRepository);
verifyZeroInteractions(mockThreadExecutor);
verifyZeroInteractions(mockPostExecutionThread);
}
@Test
@SuppressWarnings("unchecked")
public void testThereShouldNotBeAnyInteractionWithParams() {
Optional params = mock(Optional.class);
getUserList.buildUseCaseObservable(params);
verify(mockUserRepository).users();
verifyZeroInteractions(params);
}
}
@@ -0,0 +1,49 @@
/**
* Copyright (C) 2016 Fernando Cejas Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fernandocejas.android10.sample.domain.interactor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(MockitoJUnitRunner.class)
public class ParamsTest {
private Params params;
@Before
public void setUp() {
params = Params.create();
}
@Test
public void testShouldReturnIntValue() {
params.putInt("key01", 3);
assertThat(params.getInt("key01", 5)).isEqualTo(3);
}
@Test
public void testShouldReturnIntDefaultValue() {
params.putInt("key01", 3);
params.putInt("key02", 4);
assertThat(params.getInt("key03", 5)).isEqualTo(5);
}
}
Oops, something went wrong.

0 comments on commit dfd61c2

Please sign in to comment.