How to add native unit test target to gradle on Android Studio - gradle

Currently I'm developing a mostly native Android application in Android Studio. I would like to unit test my 'business logic' c++ classes and run them together with my java unit tests. My test target should:
1. Create a library with all the code I want to test
2. Compile a test main executable
3. Execute tests
4. Make it a dependency for 'java unit test' target.
I've seen some threads which deploy googletest on target machine and execute on it - but that is not my goal. I want to run tests on host machine. Any testing framework is OK, googletest would be fine.
I started with baby steps, that is - I wanted to create a target to compile a simple executable in existing build.gradle file. I struggled badly, however. I added the following:
apply plugin: 'cpp'
model {
components {
nativeTestSources(NativeExecutableSpec) {
sources.cpp {
source {
srcDir "testdir"
include "**/*.cpp"
}
}
}
}
}
I got the following Error:(65, 0) Cannot add Mutate rule 'org.gradle.language.base.plugins.ComponentModelBasePlugin$Rules#closeSourcesForBinaries(org.gradle.platform.base.BinaryContainer, org.gradle.language.base.ProjectSourceSet)' for model element 'binaries' when element is in state GraphClosed.
Can anyone point me to the right direction? Ideally an existing project cointaining a similar target I could look up to. I'm yet to find one.
I use Android Studio 1.3.1 with Gradle 2.4.

Related

IntelliJ + Gradle Multiproject: How to tell how the target source set is called?

we are currently checking, whether we can switch from Eclipse to IntelliJ as an IDE.
In this project we are using gradle multi projects whose structure looks something like this:
Project
|-ProjectA
|-ProjectAImpl
|-main*
|-ProjectATest
|-test*
|-ProjectB
|-ProjectBImpl
|-main*
|-ProjectBTest
|-test*
= Source set or in IntelliJ it seems a module.
The ProjectBTest has a dependency to ProjectATest, which is configured as
compile project(":ProjectA:ProjectATest")
This always worked properly with Eclipse but in IntelliJ I'm having the problem, that the ProjectBTest is configured such, that it is looking for a module named "Project.ProjectA.ProjectATest.main", instead of "Project.ProjectA.ProjectATest.test"
This module can obviously not be found, leading to a lot of compiler errors.
Can maybe somebody give me a hint how I can tell IntelliJ or gradle here to take the proper module?
Thank you very much.
This is standard Gradle functionality. Unless you have other Gradle customizations (like feature variants or changing the source directories for a source set), project dependencies will naturally target the main source set.
There are several ways to solve this, but two primary ones that stand out to me:
Use Gradle's Java test fixtures.
The "test" source set is not naturally inheritable in any way in Gradle. There is no built-in consumable configuration that provides test classes to downstream projects. However, Java test fixtures allow you to use a separate testFixtures source set which is shareable. To do this, you would do the following:
Add the java-test-fixtures plugin to all projects which need to produce shared test sources
Move your shared test sources to <project directory>/src/testFixtures (ideally this would include as few actual test classes as possible, but rather just shareable test logic instead)
Change your dependency references to point to the upstream project(s)' test fixtures artifact: testImplementation(testFixtures(project(":ProjectA:ProjectATest"))
Register a tests configuration which includes the test classes as an output.
project.configurations.register("tests") {
extendsFrom(project.configurations[JavaPlugin.TEST_RUNTIME_CONFIGURATION_NAME])
}
tasks.register("testJar", Jar::class) {
classifier.set("test-classes")
from(project.the<SourceSetContainer>()[SourceSet.TEST_SOURCE_SET_NAME].output)
}
project.artifacts.add("tests", project.tasks.named("testJar"))
Downstream projects:
dependencies {
compile(project(":ProjectA:ProjectATest", "tests"))
}
None of the above code is tested. It may require some adjustments.
Java test fixtures are a supported way to produce shareable test sources, so they should be preferred, but the tests configuration may be quicker to implement, depending on your use case.

How can I have gradle multi-project deps that are also standalone libraries?

What I'd ultimately like to achieve is having a top level project that can clone all of my deps, and make them rebuild as necessary. While still allowing them to build by themselves in my CI environment.
my project structure looks like this
rpf/
is/
sec/
sec has a dependency on is, is does have some deps on some of my other libraries, but currently they are not pulled in to the project for convenience sake in rapid development (though I would like them to be, ultimately they shouldn't be changing frequently which is why I want them separate).
this is a snippet of my dependency resolution in sec
dependencies {
implementation project(':is')
implementation 'com.xenoterracide:entity-api'
implementation 'com.xenoterracide:entity-jpa:0.1.0-SNAPSHOT'
what I'd like to do, is reference :is as implementation com.xenoterracide:is:0.1.0-SNAPSHOT while retaining the compile project before this one, so that if I change is, I don't have to install the dep before I can use it.
using gradle 4.3.1
update
tried this for the composite build, in my rpf/settings.gradle
include 'is', 'sec'
includeBuild('sec') {
dependencySubstitution {
substitute module('com.xenoterracide.rpf:is') with project(':is')
}
}
but
org.gradle.api.GradleException: Included build 'sec' collides with subproject of the same name.
given the example in the docs for a composite build, I'm uncertain which parameters should be which for my use case

Android Studio 3.0 NoClassDefFoundError after UPDATE GRADLE to 4+

I made a project with two modules - an Android application and a java library. After upgrading studio to v3.0, I get NoClassDefFoundError, only when I run the main() method from the java-lib module.
I did not make any changes to the build.gradle files, everything was automatic. implementation / api / compileOnly / runtimeOnly methods do not change.
I see information about switching to a new plug-in, it says about "Declare flavor dimensions". I have a problem with the translation of this and will soon go mad.
I tried:
classpath 'com.android.tools.build:gradle:3.0.0'
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-rc-4-all.zip
Help me migrate to GRADLE 4+.
You know, I've probably found the answer to my own question. I'm sure that many people have a project with two modules. The Android module works well with the new GRADLE 4+, and the second module as a java project (not a library) does not work with the new GRADLE 4+.
Result of search for the answer: LibGDX - GitHub
As stated in Android Developer Documentation:
In some cases, you may want to combine configurations from multiple product flavors. For example, you may want to create different configurations for the "full" and "demo" product flavors that are based on API level. To do this, the Android plugin for Gradle allows you to create groups of product flavors, called flavor dimensions. When building your app, Gradle combines a product flavor configuration from each flavor dimension you define, along with a build type configuration, to create the final build variant. Gradle does not combine product flavors that belong to the same flavor dimension.
You must specify at least one flavorDimension for Android Studio 3.0 & Gradle 4+
Most importantly, even if you don't have different flavors, you must specify at least one flavorDimension & apply it to all your productFlavors. That will solve your error. In your build.gradle file:
flavorDimensions "dummy"
productFlavors {
demo {
// Assigns this product flavor to the "dummy" flavor dimension.
dimension "dummy"
...
}
full {
dimension "dummy"
...
}

Kotlin Modules with Gradle Multi-Project

Kotlin got rid of package level visibility for module level visibility. I think that was a great idea, except it's difficult to get multiple Kotlin modules working in a Gradle multi-project setup.
I'm using Gradle Wrapper 3.1, with Android Studio 2.2 and Kotlin 1.0.4
Here is my structure:
Project
----myapp (android application)
----lib (android library)
----commons (android library)
// myapp/build.gradle
dependencies {
compile project(':lib')
}
// lib/build.gradle
dependencies {
compile project(':commons')
}
When I try to sync or build I get the following error:
Error:A problem occurred configuring project ':lib'.
Cannot change dependencies of configuration ':lib:default' after it has been included in dependency resolution.
The only thing that has worked is to make sure that the module names have a lexical order that matches the order they need to be built in, which is ridiculous, and not a proper solution.
I know I can publish lib and commons as artifacts, but I'd really prefer to not do that.
Anyone have any suggestions?

Why doesn't VS2010 copy all DLLs in /bin/debug to the unit test directory?

I have a unit test which depends on some code that uses MEF. When I run the test, MEF (I believe) MEF tries to load all dependent DLLs for all the DLLs in the unit test's executing directory.
The problem is that VS2010 for some reason isn't copying all the DLLs from the /bin/debug directory to the unit test's executing directory, and I don't know why. Here's an example:
Unit test is complaining is can't load assembly A, so I include project B which assembly A has as a dependency. In the /bin/debug folder for the unit test project, all the DLLs are in there, but when I look at the unit test's executing directory, assembly A isn't there.
I could start adding DLLs as refs to the unit test project one by one, but I feel like I should have to.
Thoughts?
thanks,
Mark
Maybe the DeploymentItem attribute can help, http://msdn.microsoft.com/en-us/library/ms182475.aspx:
For the parameter of the DeploymentItem attribute, specify the folder
or file that you want to deploy for this test. You can use either an
absolute path or a relative path. Relative paths are relative to the
RelativePathRoot setting found in the .testrunconfig file.
[TestMethod]
[DeploymentItem("MyTestProject\\testdatasource.mdb")]
public void TestMethod1()
{
// TODO: Add test logic here
}
You can add the project as a reference and it will sort it out.
Right click add ref project tab.
Dont ref the dll itself in teh bin\debug folder.
As test projects are simply extensions of the production code, it's not uncommon to share the same dependencies. In some cases, excluding a dependency may compile fine but will fail when the code under test tries to load a missing dependency at runtime (as you've discovered). If your tests however have to use a dependency in the test code, you'll find that you won't be able to compile without referencing that dependency.
Also keep in mind that when you execute a TestRun with MSTest, it's not the compilation process that copies the assemblies -- there's a post compilation step that copies the dependencies for the tests to a specialized "test run" folder, typically under TestResults. Visual Studio supports a feature called "Test Deployment" that can copy additional test data, etc to the test run.
The other element at play here may be the dynamic composition nature of MEF. One of the key benefits of MEF is that it follows a plugin model that dynamically loads assemblies into your application at runtime: simply drop in new assemblies and MEF will pick them up. As such, it's common that the design of the main application will not have direct references to these dynamically loaded assemblies. If you're using MEF in your tests to dynamically load tests, these tests must be copied (using Test Deployment) or referenced as part of the test project.

Resources