I have an Android application.
I want to scan for all classes within a package for a specify annotation.
I have:
package com.sample.package;
import com.sample.core.Controller;
import com.sample.core.ProtocolId;
#Controller
public class OtherController implements ControllerInterface{
#ProtocolId(id=100)
public void doSomething(){
//do something
}
}
I'm finding for classes annotated with #Controller for a specify #ProtocolId number.
I'm using Google Reflections library.
Here is how I'm scanning:
package com.sample.package;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import com.sample.core.Controller;
import com.sample.core.ProtocolId;
public class FrontController {
public void executeProperControllerMethodBasedOnId(){
Reflections ref = new Reflections("com.sample.package");
Set<Class<?>> classes = ref.getTypesAnnotatedWith(Controller.class);
System.out.println(classes.size()); //THE SIZE IS 0!!!
//The reflection doesn't worked! It didn't found any class!
}
}
The above code doesn't find any class annotated with specify annotation. Is
there something which I miss when I'm using google reflection library on
android?
Related
When compiling the following example from the robolectric migration guide
package com.jongla.soundmash.robolectric
import org.robolectric.shadows.ShadowApplicationPackageManager
import org.robolectric.annotation.Implements
import android.app.ApplicationPackageManager
#Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
class MyCustomPackageManager extends ShadowApplicationPackageManager {
}
AndroidStudio is giving me Unresolved reference: ApplicationPackageManager. Does anyone know what I need to do to get this example to compile? Do I need some additional testCompile package in gradle?
When I was looking through Roboloectric source code, I ve spotted attribute className to specify class name instead. And it works like magic.
#Implements(className = "android.app.ApplicationPackageManager", inheritImplementationMethods = true)
public class MyCustomPackageManager extends ShadowApplicationPackageManager {
}
Migration document is clearly incorrect, when suggesting to use value as ApplicationPackageManager class is private and not visible for user code.
I'm using Green Coffee library to run Cucumber scenarios in my instrumentation tests. I followed example provided by repo step-by-step, but here's the error:
junit.framework.AssertionFailedError: Class pi.survey.features.MembersFeatureTest has no public constructor TestCase(String name) or TestCase()
And when I try to add default constructor to the class like provided here, it says
no default constructor available in
'com.mauriciotogneri.greencoffee.GreenCoffeeTest'
Here's my test's source code:
package pi.survey.features;
import android.support.test.rule.ActivityTestRule;
import com.mauriciotogneri.greencoffee.GreenCoffeeConfig;
import com.mauriciotogneri.greencoffee.GreenCoffeeTest;
import com.mauriciotogneri.greencoffee.Scenario;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import pi.survey.MainActivity;
import pi.survey.steps.memberSteps;
#RunWith(Parameterized.class)
public class MembersFeatureTest extends GreenCoffeeTest {
#Rule
public ActivityTestRule<MainActivity> activity = new ActivityTestRule<>(MainActivity.class);
public MembersFeatureTest(Scenario scenario) {
super(scenario);
}
#Parameterized.Parameters
public static Iterable<Scenario> scenarios() throws IOException {
return new GreenCoffeeConfig()
.withFeatureFromAssets("assets/members.feature")
.scenarios();
}
#Test
public void test() {
start(new memberSteps());
}
}
And my members.feature source:
Feature: Inserting info to server
Scenario: Invalid members
When I introduce an invalid members
And I press the login button
Then I see an error message saying 'Invalid members'
Regarding the questions about the constructors. Due to the fact that tests in GreenCoffee require:
#RunWith(Parameterized.class)
The static method annotated with #Parameters must return a list of something (but not necessarily Scenario). The examples in the documentation simply return a list of scenarios, that's why the constructor must take a single Scenario as a parameter.
However, you can create a class that encapsulates the scenario and other objects that you may need to pass to the constructor. For example, given the following class:
public class TestParameters
{
public final String name;
public final Scenario scenario;
public TestParameters(String name, Scenario scenario)
{
this.name = name;
this.scenario = scenario;
}
}
You can write:
public TestConstructor(TestParameters testParameters)
{
super(testParameters.scenario);
}
#Parameters
public static Iterable<TestParameters> parameters() throws IOException
{
List<TestParameters> testParametersList = new ArrayList<>();
List<Scenario> scenarios = new GreenCoffeeConfig()
.withFeatureFromAssets("...")
.scenarios();
for (Scenario scenario : scenarios)
{
testParametersList.add(new TestParameters(scenario.name(), scenario));
}
return testParametersList;
}
In this way you can receive multiple values (encapsulated in an object) in the test constructor.
Solved problem by just fixing the structure.
code details in this commit
I need to mock some custom class (create for it a shadow).
I have already read on http://robolectric.org/custom-shadows/ how to do this.
so, i have some class:
public class MyClass {
public static int regularMethod() { return 1; }
}
I create a shadow:
#Implements(MyClass.class)
public class MyShadowClass {
#Implementation
public static int regularMethod() { return 2; }
}
And i set the shadow in Test-class:
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, shadows={MyShadowClass.class})
public class MyTest {
#Test
public void testShadow() {
assertEquals(2, MyClass.regularMethod());
}
}
But the shadow is not used.
java.lang.AssertionError:
Expected :2
Actual :1
How to make any custom shadow visible for RobolectricGradleTestRunner?
I have already tried:
http://www.codinguser.com/2015/06/how-to-create-shadow-classes-in-robolectric-3/
https://github.com/jiahaoliuliu/RobolectricSample/blob/master/app-tests/src/main/java/com/jiahaoliuliu/robolectricsample/RobolectricGradleTestRunner.java
Mock native method with a Robolectric Custom shadow class
but i get various compilation errors, such as
InstrumentingClassLoaderConfig not found
Setup not found
how to use custom shadows correctly in robolectric 3.0?
Custom shadows should be avoided and must be a last ditch resort. It should only be used if you cannot do much refactor in your code which is preventing you from running your tests like a native method call. It's better to mock the object of that class or spy using powermock or mockito than custom shadow it. If it's a static method, then use powermock.
In our project, we had a class which had some native methods and it was the config class used everywhere in the app. So we moved the native methods to another class and shadowed that. Those native methods were failing the test cases.
Anyways here's how you can custom shadow in robolectric 3.0:
Create a custom test runner that extends RobolectricGradleTestRunner:
public class CustomRobolectricTestRunner extends RobolectricGradleTestRunner {
public CustomRobolectricTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
public InstrumentationConfiguration createClassLoaderConfig() {
InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder();
builder.addInstrumentedPackage("com.yourClassPackage");
return builder.build();
}
Make sure that that the package doesn't contain any test cases that you are running using robolectric.
I am Jiahao, the creator of the second repository that you are referring.
First of all thanks for to check my code. I do many researches on Android and I am glad that my research is useful for someone else.
Then, the Shadow about Robolectric. I am using Robolectric 3.1 in this project, to test how Robolectric 3 works with MarshMallow:
https://github.com/jiahaoliuliu/robolectricForMarshmallow
I have been testing the new Runtime Permission Manager, as well as shadowing application and activities.
Here is sample code of the shadowed activity:
import android.content.Context;
import com.jiahaoliuliu.robolectricformarshmallow.controller.MainController;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
/**
* Created by Jiahao on 7/18/16.
*/
#Implements(MainController.class)
public class MainControllerShadow {
public void __constructor__ (Context context) {
// Not do anything
}
#Implementation
public String getTextToDisplay(boolean permissionGranted) {
return "Test";
}
}
https://github.com/jiahaoliuliu/robolectricForMarshmallow/blob/master/app/src/test/java/com/jiahaoliuliu/robolectricformarshmallow/shadow/MainControllerShadow.java
And this is how I am using it in the unit test:
package com.jiahaoliuliu.robolectricformarshmallow;
import com.jiahaoliuliu.robolectricformarshmallow.shadow.MainControllerShadow;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import static org.junit.Assert.*;
/**
* Created by Jiahao on 6/30/16.
*/
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, manifest = Config.NONE, application = FoolApplication.class,
shadows = { MainControllerShadow.class}, sdk = 18)
public class MainActivityTest {
private MainActivity mMainActivity;
#Before
public void setUp() throws Exception {
mMainActivity = Robolectric.setupActivity(MainActivity.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testOnCreate() throws Exception {
// Simple test to know that it works
assertTrue(true);
}
}
https://github.com/jiahaoliuliu/robolectricForMarshmallow/blob/master/app/src/test/java/com/jiahaoliuliu/robolectricformarshmallow/MainActivityTest.java
As you can see, I am not using customized Gradle Test Runner. I have checked the source code of Robolectric, for version 3.0 and 3.1 (latest) it is good enough to just specify the shadow classes in the header.
I hope it helps
I am creating an AIDL interface that uses an object type from an android library that is part of a different project. I can import and use the type fine in my service, but I can not import it in my AIDL interface.
package com.mysite.service;
import com.othersite.library.MyObject;
interface IMyService {
int getPid();
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
MyObject getObjects();
}
The error is:
couldn't find import for class com.othersite.library.MyObject
You must create a separate .aidl file for each class you wish to use
within your service that declares that class as parcelable.
There is a blog post about this issue here.
In camera.java, I need to get property in system. However, I can't import android.os.SystemProperties, compile camera always complains:
packages/apps/Camera/src/com/android/camera/Camera.java:53: cannot find symbol
symbol : class SystemProperties
location: package android.os
import android.os.SystemProperties;
In the beginning of camera.java, I included:
import android.os.Message;
import android.os.MessageQueue;
import android.os.SystemClock;
import android.os.SystemProperties; /* (this is in line 53)*/
It seems SystemProperties is not in android.os package, but I have checked the frameworks source code, it's indeed in it.
This happen in camera app. I found many apps under packages/app dir using SystemProperties in this manner. It's really strange.
SystemProperties class is setted 'hide' annotation.
So you want to use this class in application layer,
you have to use refelection.
the definition of SystemProperties class is below.
package android.os;
/**
* Gives access to the system properties store. The system properties
* store contains a list of string key-value pairs.
*
* {#hide}
*/
public class SystemProperties
i have encounter the same problem as you have, and i use the code below, and solve the problem by using refelection. hope it would be help
//set SystemProperties as you want
public static void setProperty(String key, String value) {
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method set = c.getMethod("set", String.class, String.class);
set.invoke(c, key, value );
} catch (Exception e) {
Log.d(LOGTAG, "setProperty====exception=");
e.printStackTrace();
}
}