Здравствуйте, уважаемое сообщество! Я прошу помощи. Я уже много раз искал ответ на этот вопрос, но не могу его найти.
Я пишу Android приложение с использованием Rx Java. Я борюсь с модульным тестом, потому что следующий код дает мне ошибку подтверждения:
@RunWith(JUnit4.class)
public class MusicRepositoryImplementationTest {
private MusicRepository musicRepository;
private ArtistDomainDataMapper artistDomainDataMapper;
private SongDomainDataMapper songDomainDataMapper;
@Mock
private LocalDataSource localDataSource;
@Mock
private RemoteDataSource remoteDataSource;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
artistDomainDataMapper = new ArtistDomainDataMapper();
songDomainDataMapper = new SongDomainDataMapper();
musicRepository = new MusicRepositoryImplementation(
this.artistDomainDataMapper,
this.songDomainDataMapper,
localDataSource,
remoteDataSource
);
}
@Test
public void test_getTopArtists_remote_and_local_success() {
List<ArtistData> artistDataList = Generator.getArtistsDataList();
List<ArtistEntity> artistEntityList = artistDataList
.stream()
.map(it -> artistDomainDataMapper.from(it))
.collect(Collectors.toList());
Mockito.when(localDataSource.getTopArtists())
.thenReturn(Observable.just(artistDataList));
Mockito.when(remoteDataSource.getTopArtists())
.thenReturn(Observable.just(artistDataList));
TestObserver testObserver = musicRepository.getTopArtists().test();
Mockito.verify(localDataSource, times(1)).getTopArtists();
testObserver
.assertSubscribed()
.awaitCount(1)
.assertValueSet(artistEntityList)
.assertComplete()
.dispose();
}
}
это дает мне ошибку:
java.lang.AssertionError: Value not in the expected collection: [domain.main.entities.ArtistEntity@193f604a, domain.main.entities.ArtistEntity@20f5239f] (class: ArrayList) (latch = 0, values = 1, errors = 0, completions = 1)
пожалуйста, посмотрите на реализацию:
public class MusicRepositoryImplementation implements MusicRepository {
private ArtistDomainDataMapper artistDomainDataMapper;
private SongDomainDataMapper songDomainDataMapper;
private LocalDataSource localDataSource;
private RemoteDataSource remoteDataSource;
@Inject
public MusicRepositoryImplementation(
ArtistDomainDataMapper artistDomainDataMapper,
SongDomainDataMapper songDomainDataMapper,
LocalDataSource localDataSource,
RemoteDataSource remoteDataSource
) {
this.artistDomainDataMapper = artistDomainDataMapper;
this.songDomainDataMapper = songDomainDataMapper;
this.localDataSource = localDataSource;
this.remoteDataSource = remoteDataSource;
}
@Override
public Observable<List<ArtistEntity>> getTopArtists() {
Observable<List<ArtistEntity>> localTopArtistsObservable = localDataSource
.getTopArtists()
.flatMapIterable(list -> list)
.map(item -> artistDomainDataMapper.from(item))
.toList()
.toObservable();
return remoteDataSource.getTopArtists()
.map(list -> {
localDataSource.saveTopArtists(list);
return list;
})
.flatMapIterable(list -> list)
.map(item -> artistDomainDataMapper.from(item))
.toList()
.toObservable()
.onErrorResumeNext(localTopArtistsObservable);
}
код для сопоставителя, который я использую внутри цепочки:
public class ArtistDomainDataMapper implements Mapper<ArtistData, ArtistEntity> {
@Inject
public ArtistDomainDataMapper() {
}
@Override
public ArtistEntity from(ArtistData artistData) {
return new ArtistEntity(
artistData.getName(),
artistData.getArtistImageUrl()
);
}
Конечно, я пробовал не только basi c AssertValueSet (), но и AssertValue () и использование сравнений массивов в lambda Выражение.
Что еще я могу добавить, так это аналогичный тест, который я написал для другого слоя, и он проходит. Интересно, может ли это быть вызвано тем, что используется инъекция планировщика и все тестируемое вызывается в Schedulers.trampoline (), но я попытался использовать в тесте метод subscribeOn (Schedulers.trampoline ()) для getTopArtists (), но это не так. работать тоже. Пожалуйста, посмотрите на рабочий:
@RunWith(MockitoJUnitRunner.class)
public class getTopArtistsTaskTest {
private GetTopArtistsTask getTopArtistsTask;
Void avoid;
@Mock
private MusicRepository musicRepository;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
getTopArtistsTask = new GetTopArtistsTask(musicRepository, Schedulers.trampoline(), Schedulers.trampoline());
}
@Test
public void test_getTopArtists_success() {
List<ArtistEntity> artistsList = Generator.getArtistsEntitiesList();
Mockito.when(musicRepository.getTopArtists()).thenReturn(Observable.just(artistsList));
TestObserver testObserver = getTopArtistsTask.buildUseCase(avoid).test();
Mockito.verify(musicRepository, times(1)).getTopArtists();
testObserver.assertSubscribed()
.assertValue(artistsList)
.assertComplete()
.dispose();
}
Реализация выглядит следующим образом:
public class GetTopArtistsTask extends ObservableUseCase<List<ArtistEntity>, Void> {
private MusicRepository musicRepository;
@Inject
public GetTopArtistsTask(MusicRepository musicRepository, Scheduler foregroundScheduler, Scheduler backgroundScheduler) {
super(foregroundScheduler, backgroundScheduler);
this.musicRepository = musicRepository;
}
@Override
protected Observable<List<ArtistEntity>> generateObservable(Void aVoid) {
return this.musicRepository.getTopArtists();
}
}
public abstract class ObservableUseCase<Return, Input> {
private Scheduler foregroundScheduler;
private Scheduler backgroundScheduler;
public ObservableUseCase(Scheduler foregroundScheduler, Scheduler backgroundScheduler) {
this.foregroundScheduler = foregroundScheduler;
this.backgroundScheduler = backgroundScheduler;
}
protected abstract Observable<Return> generateObservable(Input input);
public Observable<Return> buildUseCase(Input input){
return generateObservable(input)
.subscribeOn(backgroundScheduler)
.observeOn(foregroundScheduler);
}
}
Если что-то не так с вопросом, пожалуйста, поправьте меня. Просьба о помощи:)