Android instrumentation test failed due to mockito - unit-testing

Hi i am getting the following error
org.koin.error.BeanInstanceCreationException: Can't create definition for 'Single [name='NetworkControllerContract',class='com.network.contract.NetworkControllerContract']' due to error :
Mockito cannot mock this class: class com.network.NetworkController.
I have manually made those classes open..
open class NetworkController constructor(private val networkHelper: NetworkHelperContract) : NetworkControllerContract{.....}
open interface NetworkControllerContract {
}
//my test class
#RunWith(AndroidJUnit4::class)
class MyUnitTest: KoinTest {
single<NetworkControllerContract> {
Mockito.mock(NetworkController::class.java) //where it crashes
}
val networkController: NetworkControllerContract by inject()
}
Dependencies i use
def mockito = "2.21.0"
//android instrumental test
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.ext:truth:1.1.0'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation('androidx.arch.core:core-testing:2.0.0') {
exclude group: 'org.mockito:mockito-core'
}
androidTestUtil 'androidx.test:orchestrator:1.1.1'
androidTestImplementation 'com.github.tmurakami:dexopener:2.0.0'
androidTestImplementation 'com.jraska.livedata:testing-ktx:0.6.0'
androidTestImplementation 'com.jraska.livedata:testing:0.6.0'
androidTestImplementation "org.mockito:mockito-core:$mockito"
androidTestImplementation("org.mockito:mockito-android:$mockito") {
exclude group: 'org.mockito'
}
androidTestImplementation('org.koin:koin-test:1.0.2') {
exclude group: 'org.mockito'
}
testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-core:$mockito"
testImplementation "org.mockito:mockito-android:$mockito"
testImplementation "org.mockito:mockito-inline:$mockito"
testImplementation 'org.koin:koin-test:1.0.2'
testImplementation 'androidx.test.ext:junit:1.1.0'
testImplementation 'androidx.arch.core:core-testing:2.0.0'
testImplementation 'com.jraska.livedata:testing-ktx:0.6.0'
testImplementation 'com.jraska.livedata:testing:0.6.0'
testImplementation 'androidx.test.ext:truth:1.1.0'

It is my decision for mocking
#RunWith(AndroidJUnit4::class)
class DashboardFragmentTest : KoinTest {
#Rule
#JvmField
val activityRule = ActivityTestRule(SingleFragmentActivity::class.java, true, true)
#Rule
#JvmField
val executorRule = TaskExecutorWithIdlingResourceRule()
#Rule
#JvmField
val countingAppExecutors = CountingAppExecutorsRule()
private val testFragment = DashboardFragment()
private lateinit var dashboardViewModel: DashboardViewModel
private lateinit var router: Router
private val devicesSuccess = MutableLiveData<List<Device>>()
private val devicesFailure = MutableLiveData<String>()
#Before
fun setUp() {
dashboardViewModel = Mockito.mock(DashboardViewModel::class.java)
Mockito.`when`(dashboardViewModel.devicesSuccess).thenReturn(devicesSuccess)
Mockito.`when`(dashboardViewModel.devicesFailure).thenReturn(devicesFailure)
Mockito.`when`(dashboardViewModel.getDevices()).thenAnswer { _ -> Any() }
router = Mockito.mock(Router::class.java)
Mockito.`when`(router.loginActivity(activityRule.activity)).thenAnswer { _ -> Any() }
StandAloneContext.loadKoinModules(hsApp + hsViewModel + api + listOf(module {
single(override = true) { router }
factory(override = true) { dashboardViewModel } bind ViewModel::class
}))
activityRule.activity.setFragment(testFragment)
EspressoTestUtil.disableProgressBarAnimations(activityRule)
}
#After
fun tearDown() {
activityRule.finishActivity()
StandAloneContext.closeKoin()
}
#Test
fun devicesCall() {
onView(withId(R.id.rv_devices)).check(ViewAssertions.matches(ViewMatchers.isCompletelyDisplayed()))
Mockito.verify(dashboardViewModel, Mockito.times(1)).getDevices()
}
}

Problem is in your setup:
testImplementation "org.mockito:mockito-android:$mockito"
This dependency uses Android internals, which aren't available when you run Unit tests.

Related

Unresolved reference: TestCoroutineDispatcher

I am trying to test room database insertion and fetching with the help of TestCoroutineDispatchers and runBlockingTest. As I need the context for creating a database instance, I tried to achieve the test in androidTest, but I am getting below error. Can any one please help me out with a solution.
I am following the instructions written at this link as follows https://medium.com/#eyalg/testing-androidx-room-kotlin-coroutines-2d1faa3e674f
"Unresolved reference: TestCoroutineDispatcher"
"Unresolved reference: TestCoroutineScope"
"Unresolved reference: runBlockingTest"
#ExperimentalCoroutinesApi
#RunWith(AndroidJUnit4::class)
class PokemonDatabaseTest {
private lateinit var pokemonDao : PokemonFavouriteDao
private lateinit var db : PokemonDatabase
val testDispatcher = TestCoroutineDispatcher()
val testScope = TestCoroutineScope(testDispatcher)
#Before
fun setUp() {
db = Room
.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().context, PokemonDatabase::class.java)
.setTransactionExecutor(testDispatcher.asExecutor())
.setQueryExecutor(testDispatcher.asExecutor()).build()
pokemonDao = db.pfDao
}
#Test
fun storeFavouritePokemon() = runBlockingTest {
val pokemon = DataFactory.makePokemon()
assertThat(pokemonDao.getFavouritePokemon(), null)
}
}
And I am using below dependencies :
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test:rules:1.1.0'
testImplementation 'androidx.test:core:1.2.0'
testImplementation "org.robolectric:robolectric:4.0.2"
def archCoreVersion = '2.1.0'
def espressoCoreVersion = "3.3.0"
def espressoVersion = '3.3.0'
espressoCore: "androidx.test.espresso:espresso-core:$espressoCoreVersion",
espressoContrib : "androidx.test.espresso:espresso-contrib:$espressoVersion",
espressoIntents : "androidx.test.espresso:espresso-intents:$espressoVersion",
espressoResource: "androidx.test.espresso:espresso-idling-resource:$espressoVersion",
coreRuntime : "androidx.arch.core:core-runtime:$archCoreVersion",
coreTesting : "androidx.arch.core:core-testing:$archCoreVersion"
You declared testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2' for your unit tests.
But if you want to use TestCoroutineDispatcher for androidTest you have to declare it's dependency as well: androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'.
Same for other dependencies you wanna use for androidTest's.

Mocking suspend function with Mockito returns null

I have the following classes
interface CarsApi {
suspend fun fetchCar() : Car
}
class FetchCarUseCase(private val carsApi: CarsApi) {
suspend fun execute: Car = withContext(dispatcherProvider.io()) {
carsApi.fetchCar()
}
}
class ViewModel(private val fetchCarUseCase: FetchCarUseCase) {
private var car: Car
suspend fun retrieveCar() {
car = fetchCarUseCase.execute()
}
}
I want to write an ermetic test for the viewModel and the useCase:
#Test
fun testCarFetching() = runBlockingTest {
val aCar = Car()
val mockApi = mock<CarsApi>()
`when`(mockApi.fetchCar()).thenReturn(aCar)
val fetchCarUseCase = FetchCarUseCase(mockApi)
val viewModel = ViewModel(fetchCarUseCase)
viewModel.retrieveCar()
/* assert stuff on viewModel.car*/
}
But the viewModel.car always seems to be null. Inside the test body mockApi.fetchCar() does retrieve the provided value, but inside the FetchCarUseCase it does not. Also if I remove the suspend keyword from the interface, the mocking seems to be working fine.
At the moment, due to some other conditions I cannot use Mockk library, so I'm stuck with Mockito.
Am I missing something?
The used dependencies:
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.28.2'
testImplementation('com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0') {
exclude module: 'mockito-core'
}
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.2
In case anyone else has to deal with this problem, here is the infrastructure I have build.
First, in all the classes that launch threads inject through the constructor or property a kotlinx.coroutines.DispatcherProvider. In my case it was just the useCase, but the viewModel might require it, as well.
class FetchCarUseCase(private val dispatcher: CoroutineDispatcher,
private val carsApi: CarsApi) {
suspend fun execute: Car = withContext(dispatcher) {
carsApi.fetchCar()
}
}
In the unit tests project, add a helper rule-class, in order to extract some functionality:
#ExperimentalCoroutinesApi
class CoroutineTestRule(val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()) : TestWatcher() {
val testDispatcherProvider = object : DispatcherProvider {
override fun default(): CoroutineDispatcher = testDispatcher
override fun io(): CoroutineDispatcher = testDispatcher
override fun main(): CoroutineDispatcher = testDispatcher
override fun unconfined(): CoroutineDispatcher = testDispatcher
}
override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
}
And finally the unit test looks like this:
#ExperimentalCoroutinesApi
#RunWith(MockitoJUnitRunner::class)
class ViewModelTest {
#get:Rule
var coroutinesTestRule = CoroutineTestRule()
#Test
fun testCarFetching() = coroutinesTestRule.testDispatcher.runBlockingTest {
val aCar = Car()
val mockApi = mock<CarsApi>()
`when`(mockApi.fetchCar()).thenReturn(aCar)
val fetchCarUseCase = FetchCarUseCase(mockApi)
val viewModel = ViewModel(fetchCarUseCase)
viewModel.retrieveCar()
/* assert stuff on viewModel.car*/
}
#Test
fun testCarFetchingError() = coroutinesTestRule.testDispatcher.runBlockingTest {
val aCar = Car()
val mockApi = mock<CarsApi>()
`when`(mockApi.fetchCar()).then {
throw Exception()
}
val fetchCarUseCase = FetchCarUseCase(mockApi)
val viewModel = ViewModel(fetchCarUseCase)
viewModel.retrieveCar()
/* assert stuff on erros*/
}
}
This way all the code in the unit tests runs on the same thread and in the same context.

how to resolve dependency injection in xunit?

I have a problem in creating a test unit using xunit for my services that use dependency injection.
How can i send my dependency to test class?
[Fact]
public async Task GetAllRequestsHavePagingNoFilterNoSortAsync()
{
requestViewModel.RemotePaging = true;
requestViewModel.PageSize = 10;
requestViewModel.Page = 1;
var x = await requestService.GetAsync(requestViewModel);
Assert.NotNull(x);
Assert.True(x.PageCount == requestViewModel.PageSize);
}
You need to mock the dependencies using another library, the most popular one is Moq
So, assuming you have a class like this with a dependency injected:
public class ScrapedJobService : IScrapedJobService
{
private readonly IScrapedJobRepository _scrapedJobRepository;
public ScrapedJobService(IScrapedJobRepository scrapedJobRepository)
{
_scrapedJobRepository = scrapedJobRepository;
}
public WorkingPlace FindWorkingPlace(string title)
{
...
}
}
You need mock that dependency like this:
using Moq;
using Xunit;
private readonly ScrapedJobService _sut;
private readonly Mock<IScrapedJobRepository> _scrapedJobRepo = new Mock<IScrapedJobRepository>();
public ScrapedJobServiceTest()
{
_sut = new ScrapedJobService(_scrapedJobRepo.Object);
}
[Fact]
public void Test()
{
var result = _sut.FindWorkingPlace("Remote");
Assert.Equal(WorkingPlace.Remote, result);
}
Create a startup.cs file then map the dbcontext and the irepositoryDB specification to RepositoryDB concrete class. Dependency inject the IrepositoryDB in the xunit class constructor.
namespace XUnitTestProject1
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(System.IO.Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.Development.json", false, true)
.Build();
services.AddControllers();
var connectionString = configuration.GetConnectionString("My_DbCoreConnectionString");
services.AddDbContext<MY_DB_Context>(options2 => options2.UseSqlServer(connectionString));
services.AddTransient<IRepositoryDB, RepositoryDB>();
}
}
}
XUnit
public class UnitTest1
{
private readonly IRepositoryDB _repository;
public UnitTest1(IRepositoryDB repository)
{
_repository = repository;
}
public async Task GetItems(long id)
{
IList<myItem> list= await _repository.GetItems(id);
Assert.True(list.Count>0);
}

junit test : java.lang.ClassCastException

I am trying to implement junit testing with spring data jpa application. On controller level I am trying to implement unit testing. But I am getting Test failure class cast exception error.
DepartmentController.java
#RestController
#RequestMapping("/api.spacestudy.com/SpaceStudy/Control/SearchFilter")
public class DepartmentController {
#Autowired
DepartmentService depService;
#CrossOrigin(origins = "*")
#GetMapping("/loadDepartments")
public ResponseEntity<Set<Department>> findDepName() {
Set<Department> depname = depService.findDepName();
return ResponseEntity.ok(depname);
}
}
Junit test class
#RunWith(SpringRunner.class)
#WebMvcTest(DepartmentController.class)
public class SpaceStudyControlSearchFilterApplicationTests {
#Autowired
DepartmentController depController;
#Autowired
private MockMvc mockMvc;
#MockBean
DepartmentService depService;
#SuppressWarnings("unchecked")
Set<Department> mockDepartment = (Set<Department>) new Department(21629, "170330", "Administrative Computer");
#Test
public void findDepNameTest() throws Exception {
Mockito.when(depService.findDepName()).thenReturn( mockDepartment);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
"/api.spacestudy.com/SpaceStudy/Control/SearchFilter/loadDepartments").accept(
MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println(result.getResponse());
String expected = "{nDeptId: 21629}";
JSONAssert.assertEquals(expected, result.getResponse().getContentAsString(), false);
}
}
Junit failure
java.lang.ClassCastException: com.spacestudy.model.Department cannot be cast to java.util.Set
at com.spacestudy.SpaceStudyControlSearchFilterApplicationTests.<init>(SpaceStudyControlSearchFilterApplicationTests.java:39)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
I am new to junit testing. Can any one tell me what I am doing wrong in test?
You are trying to cast a Department to Set<Department> at this line:
Set<Department> mockDepartment = (Set<Department>) new Department(21629, "170330", "Administrative Computer");
This cannot work. Instead you should create an empty set and then add the department, i.e. like this:
Set<Department> mockDepartment = new HashSet<Department>() {{
add(new Department(21629, "170330", "Administrative Computer"));
}};

Arquillan EJB3 unit test - java.lang.ClassNotFoundException

I'm running an EJB unit test with Arquillian but I receive
java.lang.ClassNotFoundException: org.jboss.arquillian.test.spi.TestRunnerAdaptorBuilder
my test class is this
#RunWith(Arquillian.class)
public class EjbTest {
#Inject
private RepAlertManagerImpl ejb;
#Deployment
public static Archive<?> createDeployment() {
return ShrinkWrap.create(JavaArchive.class, "foo.jar")
.addClasses(RepAlertManagerImpl.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void testEjb() throws IOException, SQLException {
try
{
List<Long> result = ejb.doSomething("ENTRATE");
for(Long temp:result){
System.out.println(temp);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
the jar I use for this client are
arquillian-container-test-api-1.1.7.Final;
arquillian-junit-core-1.1.7.Final;
junit-4.12
I finally solved with gradle.
My build.gradle contains:
compile 'junit:junit:4.8.2'
compile 'org.jboss.arquillian.junit:arquillian-junit-container:1.1.7.Final'
just type gradle eclipse from build.gradle file dir (project directory)