How to specify classpath ordering in Gradle - unit-testing

I need to control the ordering of jars in the testRuntime configuration.
I must make sure that robolectric-x.x.jar comes before android.jar, or else I get the dreaded RuntimeException("Stub!").
How do I do that?

Here is my complete build.gradle for running Robolectric tests against my Android app, which uses RoboGuice:
apply plugin: 'java'
androidJar = new File(System.getenv('ANDROID_HOME'), '/platforms/android-7/android.jar')
configurations { robo }
dependencies {
robo('com.pivotallabs:robolectric:1.0-RC1')
testCompile('org.roboguice:roboguice:1.1.2')
testCompile('junit:junit:4.8.2')
testCompile project (':app')
testCompile files(androidJar)
}
sourceSets.test.compileClasspath = configurations.robo + sourceSets.test.compileClasspath
sourceSets.test.runtimeClasspath = configurations.robo + sourceSets.test.runtimeClasspath
test {
excludes = ['**/MyRobolectricTestRunner.class']
}
I had to add an exclusion for the test runner, or else Gradle will throw an exception.
MyRobolectricTestRunner.java looks like this:
package com.acme.myapp;
import java.io.File;
import org.junit.runners.model.InitializationError;
import roboguice.application.RoboApplication;
import roboguice.inject.ContextScope;
import com.google.inject.Injector;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner;
public class MyRobolectricTestRunner extends RobolectricTestRunner {
public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
// Tell Robolectric where to find AndroidManifest.xml and res/
super(testClass, new File("../app"));
}
/**
* Enable injection into tests as well...
*/
#Override
public void prepareTest(Object test) {
RoboApplication myApplication = (RoboApplication) Robolectric.application;
Injector injector = myApplication.getInjector();
ContextScope contextScope = injector.getInstance(ContextScope.class);
contextScope.enter(myApplication);
injector.injectMembers(test);
}
}
And here's a sample test that illustrates injection:
package com.acme.myapp;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import roboguice.inject.InjectResource;
#RunWith(MyRobolectricTestRunner.class)
public class StringFormattingTest {
#InjectResource(R.string.info_pending_amount)
private String pendingAmountPattern;
#Test
public void testFormatInfoPendingAmount() {
String s = String.format(pendingAmountPattern, 20.0d, "EUR");
assertEquals("Only a part of your stake (20,00 EUR) was accepted", s);
}
}

This might work:
configurations { robo }
dependencies {
robo ...
testRuntime ...
}
sourceSets.test.runtimeClasspath = configurations.robo + sourceSets.test.runtimeClasspath

Related

Why is Koin scoping feature not working properly?

So scoping with Koin DI seem to throw a weird exception when KoinApplication::checkModules() method is called within a unit test. Here is the full code:
import org.koin.core.KoinApplication
import org.koin.core.component.KoinComponent
import org.koin.core.component.KoinScopeComponent
import org.koin.core.component.createScope
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.core.logger.Level
import org.koin.core.scope.Scope
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.check.checkModules
import org.koin.test.inject
import kotlin.test.BeforeTest
import kotlin.test.Test
class FixScopingTest : KoinTest {
private val component1: Component1 by inject()
private lateinit var koinApp: KoinApplication
#BeforeTest
fun setup() {
koinApp = startKoin {
modules(
module {
single { Component1() }
scope<Component1> {
scoped { Component2() }
}
}
)
// printLogger(Level.DEBUG)
}
}
#Test
fun verifyKoinApp() {
//component1.component2.print()
koinApp.checkModules()
}
}
class Component1 : KoinComponent, KoinScopeComponent {
override val scope: Scope by lazy { createScope(this) }
val component2: Component2 by inject()
}
class Component2 {
fun print() = println("Component2::print()")
}
exception 1:
com.xycompany.xyproj.xypackage.FixScopingTest > verifyKoinApp FAILED
java.lang.IllegalStateException: Missing MockProvider. Please use MockProvider.register() to register a new mock provider
at org.koin.test.mock.MockProvider.getProvider(MockProvider.kt:10)
at org.koin.test.mock.MockProvider.makeMock(MockProvider.kt:23)
at org.koin.test.check.CheckModulesKt.mockSourceValue(CheckModules.kt:102)
at org.koin.test.check.CheckModulesKt.check(CheckModules.kt:95)
at org.koin.test.check.CheckModulesKt.checkAllDefinitions(CheckModules.kt:86)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:72)
at org.koin.test.check.CheckModulesKt.checkModules(CheckModules.kt:40)
at org.koin.test.check.CheckModulesKt.checkModules$default(CheckModules.kt:40)
at com.xycompany.xyproj.xypackage.FixScopingTest.verifyKoinApp(FixScopingTest.kt:43)
Second weird issue appears when you uncomment the commented part so we would have usage of scoped components on DEBBUG level logger:
exception 2:
com.xycompany.xyproj.xypackage.FixScopingTest > verifyKoinApp FAILED
java.lang.NoSuchMethodError: 'double kotlin.time.Duration.toDouble-impl(long, java.util.concurrent.TimeUnit)'
at org.koin.core.time.MeasureKt.measureDurationForResult(Measure.kt:41)
at org.koin.core.scope.Scope.get(Scope.kt:189)
at com.xycompany.xyproj.xypackage.FixScopingTest$special$$inlined$inject$default$1.invoke(KoinTest.kt:53)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.xycompany.xyproj.xypackage.FixScopingTest.getComponent1(FixScopingTest.kt:20)
at com.xycompany.xyproj.xypackage.FixScopingTest.verifyKoinApp(FixScopingTest.kt:41)
SETTINGS:
Kotlin Multiplatform Project (test is run in both Andorid and Common packages with the same problem)
VERSIONS:
koin-core: 3.1.3
koin-android: 3.1.3
Looks like you need to add a MockProviderRule when using scoped. It's not required if are not using scopes.
#get:Rule
val mockProvider = MockProviderRule.create { clazz ->
// Mock with your framework here given clazz
// e.g: Mockito.mock(clazz.java)
}
And for it to work you also need to add this dependency to gradle
testImplementation "io.insert-koin:koin-test-junit4:3.1.6"
https://insert-koin.io/docs/reference/koin-test/checkmodules/#allow-mocking-with-a-junit-rule

How can I run my custom gradle task in the unit test?

I need to run my gradle task to test basic functional in the unit test:
import org.gradle.api.Project;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.Test;
public class IwillfailyouPluginTest {
#Test
public void applyPlugin() {
final Project project = ProjectBuilder.builder().build();
project.getPlugins().apply(IwillfailyouPlugin.class);
project.task("iwillfailyou").// what method should I run?
}
}
But I can not find the method to run it. Help me, please
My understanding is that ProjectBuilder is more for unit-like tests. So with what you have, you should only be asserting that a task named iwillfailyou exists, is of a certain type, and has the correct configuration.
public class IwillfailyouPluginTest {
#Test
public void applyPlugin() {
final Project project = ProjectBuilder.builder().build();
project.getPlugins().apply(IwillfailyouPlugin.class);
assertTrue(project.getTasks().getNames().contains("iwillfailyou"));
MyCustomTaskType iwillfailyou = project.getTasks().getByName("iwillfailyou");
assertEquals(123, iwillfailyou.getSomeConfig())
}
}
It looks looks you're trying to test the behavior/function of the custom task. For that sort of test, you would use TestKit.
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.io.FileWriter;
import java.nio.file.Files;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class IwillfailyouPluginFunctionalTest {
#Test
void canRunTask() throws IOException {
// Setup the test build
File projectDir = new File("build/functionalTest");
Files.createDirectories(projectDir.toPath());
writeString(new File(projectDir, "settings.gradle"), "");
writeString(new File(projectDir, "build.gradle"), "plugins {" + " id('i.will.fail.you')" + "}");
// Run the build
GradleRunner runner = GradleRunner.create();
runner.forwardOutput();
runner.withPluginClasspath();
runner.withArguments("iwillfailyou");
runner.withProjectDir(projectDir);
BuildResult result = runner.build();
// Verify the result
Assertions.assertTrue(result.getOutput().contains("someoutput from the iwillfailyou task"));
}
private void writeString(File file, String string) throws IOException {
try (Writer writer = new FileWriter(file)) {
writer.write(string);
}
}
}

How to import 'org.hamcrest.collection' in junit to test collection methods

I am using Junit 5 and getting the following error while importing collection packages
The import org.hamcrest.collection cannot be resolved
I need to validate assertThat method & hasSize() from collection for which the below import should be done.
import org.hamcrest.collection.IsEmptyCollection;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import java.awt.List;
import java.util.ArrayList;
public class PortJUnit {
PortBO portBO;
ArrayList<Port> list = new ArrayList<Port>();
#Before
public void createObjectForPort()
{
portBO = new PortBO();
}
#Test
public void testPortDetails()
{
list.add(new Port(101,"abc","cbe"));
list.add(new Port(102,"abd","chennai"));
list.add(new Port(103,"abe","bangalore"));
list.add(new Port(104,"abf","mumbai"));
list.add(new Port(105,"abg","delhi"));
String detail = "107,abh,Toronto";
portBO.addElementAtSpecfiedPosition(list, 6, detail);
assertThat(list, hasSize(6));
}
}
I suggest that you use hamcrest-core dependency.
Please try to use instead - hamcrest-all-1.3.jar and your problem will be solved.

Mockito not injecting repository mocks

I am trying to write tests for spring boot application which has repositories.
My test class looks like this:
package se.volvo.spp.controller.spp;
import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.*;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.cassandra.repository.MapId;
import org.springframework.data.cassandra.repository.support.BasicMapId;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import se.volvo.spp.BaseTest;
import se.volvo.spp.config.JacksonConfig;
import se.volvo.spp.dao.cassandra.*;
import se.volvo.spp.dto.ServiceAgentDTO;
import se.volvo.spp.exception.NotFoundException;
import se.volvo.spp.repository.AssignmentRepository;
import se.volvo.spp.repository.ServiceAgentRepository;
import se.volvo.spp.service.impl.ServiceAgentService;
import javax.inject.Inject;
import java.util.*;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class ServiceAgentControllerTest extends BaseTest {
#Autowired
private MockMvc mockMvc;
#Mock
ServiceProviderDAO serviceProviderDAO;
#Mock
ServiceTypeDAO serviceTypeDAO;
#Mock
ServiceDefinitionDAO serviceDefinitionDAO;
#Mock
ServiceAgentDAO serviceAgentDAO;
#Mock
AssignmentDAO assignmentDAO;
#Mock
ServiceAgentRepository serviceAgentRepository;
#Mock
AssignmentRepository assignmentRepository;
#InjectMocks
ServiceAgentService serviceAgentService;
#Before
public void setUp() {
serviceAgentDAO.setId(UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b"));
serviceAgentDAO.setContactEmail("joe.smith#arwe.com");
serviceAgentDAO.setContactTelephone("0735333333");
serviceAgentDAO.setEnabled(true);
serviceAgentDAO.setFirstNames("Joe");
serviceAgentDAO.setLastName("Smith");
serviceAgentDAO.setServiceDefinitionIds(Arrays.asList(UUID.fromString("9a9cb34a-4221-11e8-842f-0ed5f89f718b")));
assignmentDAO.setId(UUID.fromString("69f7cd9c-423f-11e8-842f-0ed5f89f718b"));
assignmentDAO.setCustomerId(UUID.fromString("7b479d52-423f-11e8-842f-0ed5f89f718b"));
assignmentDAO.setCustomerName("John Gill");
assignmentDAO.setServiceAgentId(UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b"));
assignmentDAO.setServiceDefinitionId(UUID.fromString("9a9cb34a-4221-11e8-842f-0ed5f89f718b"));
assignmentDAO.setServiceSlotId(UUID.fromString("a7ff6543-4236-11e8-8706-313df4405fc7"));
assignmentDAO.setVehicle("WIN898987686");
/*when(serviceAgentRepository.findOne(BasicMapId.id("id", Mockito.any(UUID.class)))).thenAnswer(new Answer() {
#Override
public ServiceAgentDAO answer(InvocationOnMock invocationOnMock) throws Throwable {
System.out.println("ARGUMENT IS OUTSIDE :: "+(String)invocationOnMock.getArguments()[0]);
if(((String)invocationOnMock.getArguments()[0]).equals(UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b"))) {
System.out.println("ARGUMENT IS :: "+invocationOnMock.getArguments()[0]);
return serviceAgentDAO;
}
else
throw new NotFoundException("The Service Agent ID does not exist!");
}
}
);*/
//when(serviceAgentRepository.findOne(BasicMapId.id("id", AdditionalMatchers.not(Matchers.eq(UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b")))))).thenThrow (new NotFoundException("The ServiceAgent with that ID does not exist!"));
when(serviceAgentRepository.findOne(BasicMapId.id("id", UUID.class))).thenReturn (serviceAgentDAO);
List<AssignmentDAO> assignmentDAOList = Arrays.asList(assignmentDAO);
when(assignmentRepository.findByServiceAgentId(UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b"))).thenReturn(assignmentDAOList);
assignmentDAO.setServiceAgentId(null);
when(assignmentRepository.save(Mockito.any(AssignmentDAO.class))).thenReturn(assignmentDAO);
serviceAgentDAO.setEnabled(false);
when(serviceAgentRepository.save(Mockito.any(ServiceAgentDAO.class))).thenReturn(serviceAgentDAO);
}
#Test
public void testServiceAgentNotFound() throws Exception {
ObjectMapper objectMapper = JacksonConfig.createMapper();
ServiceAgentDTO serviceAgentDTO = new ServiceAgentDTO();
serviceAgentDTO.setEnabled(false);
this.mockMvc.perform(patch("/serviceagent/" + UUIDs.timeBased())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(serviceAgentDTO))).andDo(print())
.andExpect(status().isNotFound());
}
#Test
public void testServiceAgentIDNotAllowedInRequest() throws Exception {
ObjectMapper objectMapper = JacksonConfig.createMapper();
ServiceAgentDTO serviceAgentDTO = new ServiceAgentDTO();
serviceAgentDTO.setId(UUIDs.timeBased());
serviceAgentDTO.setEnabled(false);
this.mockMvc.perform(patch("/serviceagent/" + UUIDs.timeBased())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(serviceAgentDTO))).andDo(print())
.andExpect(status().isBadRequest());
}
/*
test to verify if the agent is disabled, then the agent is removed on his assignments as well
*/
#Test
public void testServiceAgentDisabledFromEnabled() throws Exception {
ObjectMapper objectMapper = JacksonConfig.createMapper();
// add a service provider
serviceProviderDAO.setId(UUID.fromString("8890e560-4170-11e8-a465-3f3e0c8fed10"));
serviceProviderDAO.setContactAddress("Torsgatan 190");
serviceProviderDAO.setContactTelephone("073q12345678");
serviceProviderDAO.setEnabled(true);
serviceProviderDAO.setName("Cleany Car");
// add a service type
serviceTypeDAO.setId(UUID.fromString("e3e0c006-4220-11e8-842f-0ed5f89f718b"));
serviceTypeDAO.setEnabled(true);
serviceTypeDAO.setName("Refuel Benzene 95");
serviceTypeDAO.setParentServiceTypeId(UUID.fromString("c1ecdf7a-4220-11e8-842f-0ed5f89f718b"));
serviceTypeDAO.setScopes(Arrays.asList("UNLOCK", "LOCK"));
// add service definition
serviceDefinitionDAO.setId(UUID.fromString("9a9cb34a-4221-11e8-842f-0ed5f89f718b"));
serviceDefinitionDAO.setEnabled(true);
serviceDefinitionDAO.setGeographicAvailability(null);
serviceDefinitionDAO.setLeadTimesInHours(24);
serviceDefinitionDAO.setMaxAdvanceTimeInDays(7);
Map<Integer, String> operatingWeekMap = new HashMap<>();
operatingWeekMap.put(1, "10:00&17:00");
operatingWeekMap.put(2, "09:00&17:00");
operatingWeekMap.put(3, "09:00&17:00");
operatingWeekMap.put(4, "09:00&17:00");
operatingWeekMap.put(5, "09:00&17:00");
operatingWeekMap.put(6, "11:00&17:00");
operatingWeekMap.put(7, "09:00&17:00");
serviceDefinitionDAO.setOperatingWeek(operatingWeekMap);
serviceDefinitionDAO.setServiceProviderId(UUID.fromString("8890e560-4170-11e8-a465-3f3e0c8fed10"));
serviceDefinitionDAO.setServiceSlotDurationInMinutes(60);
serviceDefinitionDAO.setServiceTypeId(UUID.fromString("e3e0c006-4220-11e8-842f-0ed5f89f718b"));
serviceDefinitionDAO.setTimeZoneId("Europe/London");
// we do not populate service slot as of now, since we just need to disable agent!
ServiceAgentDTO serviceAgentDTO = new ServiceAgentDTO();
serviceAgentDTO.setEnabled(false);
this.mockMvc.perform(patch("/serviceagent/" + UUID.fromString("e5cec1dc-422b-11e8-842f-0ed5f89f718b"))
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(serviceAgentDTO))).andDo(print())
.andExpect(status().isOk());
}
}
The ServiceAgentService class has the constructor injection already for the repositories.
For some reason my mocked repositories in the setup() method do not take effect.
Also, the BaseTest class looks like below
package se.volvo.spp;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = Application.class)
#AutoConfigureMockMvc
#ActiveProfiles("dev")
#Ignore
public class BaseTest {
}
Any help is highly appreciated!

How to run unit tests with dependency to an Android library module?

Whenever I try to run unit-tests for classes in my app module that depend on classes from an library module, I get this:
java.lang.NoClassDefFoundError: de/ivu/junittest/DummyData
at de.ivu.junittest.app.DummyModel.<init>(DummyModel.java:16)
at DummyModelTest.testInstantiation(DummyModelTest.java:7)
...
In the above sample, DummyData is part of the lib module, while DummyModel is part of the app module. DummyModel has a member of type DummyData, but instantiating this in the test-class DummyModelTest causes the aforementioned exception at test-time.
The project structure is as follows:
JUnitTestProject
app [module]
src
main
java
de.ivu.junittest.app
DummyModel.java
...
...
test
java
de.ivu.junittest.app
DummyModelTest.java
...
lib [module]
src
main
java
de.ivu.junittest
DummyData.java
...
...
The build.gradle for the app module contains the following:
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
defaultConfig {
minSdkVersion 7
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
sourceSets {
unitTest {
java.srcDir file('src/test/java')
resources.srcDir file('src/test/res')
}
}
configurations {
unitTestCompile.extendsFrom runtime
unitTestRuntime.extendsFrom unitTestCompile
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
compile project (':lib')
compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
unitTestCompile files("$project.buildDir/classes/release")
unitTestCompile 'junit:junit:4.+'
unitTestCompile 'org.robolectric:robolectric:2.+'
unitTestCompile 'com.google.android:android:4.+'
unitTestCompile project (':lib')
unitTestCompile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
instrumentTestCompile 'junit:junit:4.+'
instrumentTestCompile 'org.robolectric:robolectric:2.+'
}
task unitTest(type:Test, dependsOn: assemble) {
testClassesDir = project.sourceSets.unitTest.output.classesDir
classpath = project.sourceSets.unitTest.runtimeClasspath
}
check.dependsOn unitTest
And finally the source of the three java-classes, starting with DummyData:
package de.ivu.junittest;
import android.util.Log;
public class DummyData {
private int data;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
The DummyModel class:
package de.ivu.junittest.app;
import android.util.Log;
import de.ivu.junittest.DummyData;
public class DummyModel {
private DummyData data = new DummyData();
public void setData(int data) {
this.data.setData(data);
}
public int getData() {
return this.data.getData();
}
}
And finally, DummyModelTest:
import static org.junit.Assert.assertEquals;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.robolectric.RobolectricTestRunner;
import de.ivu.junittest.app.DummyModel;
#RunWith(RobolectricTestRunner.class)
public class DummyModelTest {
#Test
public void testInstantiation() {
DummyModel model = new DummyModel();
model.setData(42);
assertEquals(model.getData(), 42);
}
}
After trying more than a dozen different things, any help is deeply appreciated.
The trick is to add the other modules' classes directories as dependency. So you end up with unitTestCompile files instead of unitTestCompile project:
dependencies {
...
unitTestCompile files("../lib/classes/release")
...
}
Not very beautiful, nor very intuitive, but it works with my current setup (Gradle 1.10, Build Tools 19.0.1, and Android-Gradle-plugin 0.8).