Using Roboguice in Tests in Android Studio - android

So after spending a day or so trying to get robolectric to work with gradle using the android-gradle-plpugin I read that the creator thinks it's too much hassle and doesn't use it himself
So thats a big enough reason for me not to use it either. However now I cannot find any docs on how to set up normal android tests to run on the emulator. Its seems they all relate to eclipse. How do I get normal Android testings running with Android studio. I presume I need to modify build.gradle but how do I do that?
I would also like to use roboguice to inject my dependencies into the test cases.
EDIT
So I took a stab in the dark and I tried this but the test returns false (a fail)
public class SearchTest extends ActivityTestCase {
#Inject
private ObjectMapper objectMapper;
#Override
protected void setUp() throws Exception {
super.setUp();
RoboInjector injector = RoboGuice.getInjector(getActivity());
injector.injectMembersWithoutViews(this);
}
public void shouldSerialise() {
System.out.println("called should serialise");
Assert.assertNotNull(objectMapper);
}
}
EDIT 2
So I have tried a different approach. I followed this tutorial which does seem to run the test however I am having a problem with providing a manifest find as I get the following error,
WARNING: No manifest file found at ./AndroidManifest.xml.Falling back
to the Android OS resources only. To remove this warning, annotate
your test class with #Config(manifest=Config.NONE).
I then used this test runner instead...
public class RobolectricGradleTestRunner extends RobolectricTestRunner {
public RobolectricGradleTestRunner(Class<?> testClass) throws org.junit.runners.model.InitializationError {
super(testClass);
}
#Override protected AndroidManifest getAppManifest(Config config) {
String manifestProperty = System.getProperty("android.manifest");
if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) {
String resProperty = System.getProperty("android.resources");
String assetsProperty = System.getProperty("android.assets");
return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty),
Fs.fileFromPath(assetsProperty));
}
return super.getAppManifest(config);
}
}
With no luck. Would I be better reverting back to intellij and purely using maven?

Related

How to correctly implement and test Custom Lint Rules in Android Studio?

I'm following this tutorial and this Custom Detector Example in order to implement Custom Lint Rules. Basically what I've done is:
Create a new Android Project in Android Studio;
Create a java module for project created in step 1;
On module's build.gradle, import Lint API dependencies;
Create an Issue & IssueRegistry & CustomDetector;
Reference the IssueRegistry on module's build.gradle;
Create Unit tests;
My problem is, during the execution of my JUnits, I always receive "No Warning". When I debug the test, I can see that my Custom Detector isn't called, what am I doing wrong?
Strings.java
public class Strings {
public static final String STR_ISSUE_001_ID = "VarsMustHaveMoreThanOneCharacter";
public static final String STR_ISSUE_001_DESCRIPTION = "Avoid naming variables with only one character";
public static final String STR_ISSUE_001_EXPLANATION = "Variables named with only one character do not pass any meaning to the reader. " +
"Variables name should clear indicate the meaning of the value it is holding";
}
Issues.java
public class Issues {
public static final
Issue ISSUE_001 = Issue.create(
STR_ISSUE_001_ID,
STR_ISSUE_001_DESCRIPTION,
STR_ISSUE_001_EXPLANATION,
SECURITY,
// Priority ranging from 0 to 10 in severeness
6,
WARNING,
new Implementation(VariableNameDetector.class, ALL_RESOURCES_SCOPE)
);
}
IssuesRegistry.java
public class IssueRegistry extends com.android.tools.lint.client.api.IssueRegistry {
#Override
public List<Issue> getIssues() {
List<Issue> issues = new ArrayList<>();
issues.add(ISSUE_001);
return issues;
}
}
VariableNameDetector.java
public class VariableNameDetector extends Detector implements Detector.JavaScanner {
public VariableNameDetector() {
}
#Override
public boolean appliesToResourceRefs() {
return false;
}
#Override
public boolean appliesTo(Context context, File file) {
return true;
}
#Override
#Nullable
public AstVisitor createJavaVisitor(JavaContext context) {
return new NamingConventionVisitor(context);
}
#Override
public List<String> getApplicableMethodNames() {
return null;
}
#Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
List<Class<? extends Node>> types = new ArrayList<>(1);
types.add(lombok.ast.VariableDeclaration.class);
return types;
}
#Override
public void visitMethod(
JavaContext context,
AstVisitor visitor,
MethodInvocation methodInvocation
) {
}
#Override
public void visitResourceReference(
JavaContext context,
AstVisitor visitor,
Node node,
String type,
String name,
boolean isFramework
) {
}
private class NamingConventionVisitor extends ForwardingAstVisitor {
private final JavaContext context;
NamingConventionVisitor(JavaContext context) {
this.context = context;
}
#Override
public boolean visitVariableDeclaration(VariableDeclaration node) {
StrictListAccessor<VariableDefinitionEntry, VariableDeclaration> varDefinitions =
node.getVariableDefinitionEntries();
for (VariableDefinitionEntry varDefinition : varDefinitions) {
String name = varDefinition.astName().astValue();
if (name.length() == 1) {
context.report(
ISSUE_001,
context.getLocation(node),
STR_ISSUE_001_DESCRIPTION
);
return true;
}
}
return false;
}
}
}
build.gradle
apply plugin: 'java'
configurations {
lintChecks
}
ext {
VERSION_LINT_API = '24.3.1'
VERSION_LINT_API_TESTS = '24.3.1'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "com.android.tools.lint:lint-api:$VERSION_LINT_API"
implementation "com.android.tools.lint:lint-checks:$VERSION_LINT_API"
testImplementation "com.android.tools.lint:lint-tests:$VERSION_LINT_API_TESTS"
}
jar {
manifest {
attributes('Lint-Registry': 'br.com.edsilfer.lint_rules.resources.IssueRegistry')
}
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
TestVariableNameDetector.java
private static final String ARG_DEFAULT_LINT_SUCCESS_LOG = "No warnings.";
#Override
protected Detector getDetector() {
return new VariableNameDetector();
}
#Override
protected List<Issue> getIssues() {
return Collections.singletonList(Issues.ISSUE_001);
}
public void test_file_with_no_variables_with_length_equals_01() throws Exception {
assertEquals(
ARG_DEFAULT_LINT_SUCCESS_LOG,
lintProject(java("assets/Test.java", "public class Test {public String sampleVariable;}"))
);
}
public void test_file_with_variables_with_length_equals_01() throws Exception {
assertEquals(
ARG_DEFAULT_LINT_SUCCESS_LOG,
lintProject(java("assets/Test3.java", "public class Test {public String a;bnvhgvhj}"))
);
}
}
P.S.: on Java's module I do not have access to assetsor res folder, that is the reason why I've created a String.java and I'm using java(to, source) in my Unit test - I assumed that this java method does the same as the xml from the tutorial link I referenced at the top of this question.
It turned out that in my case the problem was with the JUnit itself. I think that the way I was attempting to simulate the file was wrong. The text below is part of the README.md of a sample project that I've created in order to document what I've learned from this API and answers the question in the title:
Create
Create a new Android Project;
Create a new Java Library Module - Custom Lint Rules are packaged into .jar libraries once they are ready, therefore the easiest way to implement them using them is inside a Java Module Library;
On module's build.gradle:
add target and source compatibility to Java 1.7;
add dependencies for lint-api, lint-checks and test dependencies;
add jar packing task containing two attributes: Manifest-Version and Lint-Registry, set the first to 1.0 and the second as the full path to a class that will later on contain the issue's catalog;
add a default tasl assemble;
[OPTIONAL]: add a task that will copy the generated .jar into ~/.android/lint;
Check REF001 and choose a Detector that best suits your needs, based on it create and implement a class to fulfill the Detector's role;
Still based on REF0001 chosen file, create and implement a Checker class, later referring to it inside Detector's createJavaVisitor() method;
for the sake of SRP, do not place Checker in the same file of Detector's class;
Copy the generated .jar file from build/lib to ~/.android/lint - if you added a task on build.gradle that does this you can skip this step;
Restart the computer - once created and moved into ~/.android/lint, the Custom Rules should be read by Lint next time the program starts. In order to have the alert boxes inside Android Studio, it is enough to invalidate caches and restart the IDE, however, to have your custom rules caught on Lint Report when ./gradlew check, it might be necessary to restart your computer;
Testing Detectors and Checkers
Testing Custom Rules is not an easy task to do - mainly due the lack of documentation for official APIs. This section will present two approaches for dealing with this. The main goal of this project is to create custom rules that will be run against real files, therefore, test files will be necessary for testing them. They can be places in src/test/resources folder from your Lint Java Library Module;
Approach 01: LintDetectorTest
Make sure you've added all test dependencies - checkout sample project's build.gradle;
Copy EnhancedLintDetectorTest.java and FileUtils.java into your project's test directory;
There is a known bug with Android Studio that prevents it from seeing files from src/test/resources folder, these files are a workaround for that;
EnhancedLintDetectorTest.java should return all issues that will be subject of tests. A nice way to do so is getting them from Issue Registry;
Create a test class that extends from EnhancedLintDetectorTest.java;
Implement getDetector() method returning an instance of the Detector to be tested;
Use lintFiles("test file path taking resources dir as root") to perform the check of the Custom Rules and use its result object to assert the tests;
Note that LintDetectorTest.java derives from TestCase.java, therefore, you're limited to JUnit 3.
Approach 02: Lint JUnit Rule
You might have noticed that Approach 01 might be a little overcomplicated, despite the fact that you're limited to JUnit 3 features. Because of that GitHub user a11n created a Lint JUnit Rule that allows the test of Custom Lint Rules in a easier way that counts with JUnit 4 and up features. Please, refer to his project README.md for details about how to create tests using this apprach.
Currently, Lint JUnit Rule do not correct the root dir for test files and you might no be able to see the tests passing from the IDE - however it works when test are run from command line. An issue and PR were created in order to fix this bug.
I'm not sure how to use the AST Api, however I'm personally using Psi and this is one of my lint checks that are working for me.
public final class RxJava2MethodCheckReturnValueDetector extends Detector implements Detector.JavaPsiScanner {
static final Issue ISSUE_METHOD_MISSING_CHECK_RETURN_VALUE =
Issue.create("MethodMissingCheckReturnValue", "Method is missing the #CheckReturnValue annotation",
"Methods returning RxJava Reactive Types should be annotated with the #CheckReturnValue annotation.",
MESSAGES, 8, WARNING,
new Implementation(RxJava2MethodCheckReturnValueDetector.class, EnumSet.of(JAVA_FILE, TEST_SOURCES)));
#Override public List<Class<? extends PsiElement>> getApplicablePsiTypes() {
return Collections.<Class<? extends PsiElement>>singletonList(PsiMethod.class);
}
#Override public JavaElementVisitor createPsiVisitor(#NonNull final JavaContext context) {
return new CheckReturnValueVisitor(context);
}
static class CheckReturnValueVisitor extends JavaElementVisitor {
private final JavaContext context;
CheckReturnValueVisitor(final JavaContext context) {
this.context = context;
}
#Override public void visitMethod(final PsiMethod method) {
final PsiType returnType = method.getReturnType();
if (returnType != null && Utils.isRxJava2TypeThatRequiresCheckReturnValueAnnotation(returnType)) {
final PsiAnnotation[] annotations = method.getModifierList().getAnnotations();
for (final PsiAnnotation annotation : annotations) {
if ("io.reactivex.annotations.CheckReturnValue".equals(annotation.getQualifiedName())) {
return;
}
}
final boolean isMethodMissingCheckReturnValueSuppressed = context.getDriver().isSuppressed(context, ISSUE_METHOD_MISSING_CHECK_RETURN_VALUE, method);
if (!isMethodMissingCheckReturnValueSuppressed) {
context.report(ISSUE_METHOD_MISSING_CHECK_RETURN_VALUE, context.getLocation(method.getNameIdentifier()), "Method should have #CheckReturnValue annotation");
}
}
}
}
}
Checkout the many more I wrote here.

Android - How to UnitTest a Logging class with mockito

I have written a class to manage logging within an android application project.
The LogManager is basically a wrapper for android.util.log
It handles logging to a file, if the application crashes, and standard debug logging.
I would like to unit test the class using JUnit.
I have tried the following but it does not seem to produce the results I would expect after reading the examples:
LogManager.class (This is a simplified version of the class I have used, for demonstration purposes)
public class LogManager implements ILogManager
{
public void log(String tag, String message)
{
Log.e(tag, message);
}
}
And here is my test class
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21)
#PrepareForTest({Log.class, LogManager.class})
public class LogManagerUnitTest
{
#Test
public void testLogConsoleInfo()
{
PowerMockito.mockStatic(Log.class);
LogManager.getInstance().log(LogLevel.INFO, "test", "test");
PowerMockito.verifyStatic(Mockito.times(1));
Log.e(anyString(), anyString());
}
}
My problem is that this passes no matter what I put.
E.g: if I instead replace the last call with Log.wtf(...) it still passes. I would have assumed that it should fail since Log.wtf was not called in the static class Log?
So my question is, why isn't this approach working as expected and what would be the correct way to do it?
I started a fresh project and was able to get it to fail tests and succeed appropriately using the following, so I'm assuming the runwith was the culprit:
#RunWith(PowerMockRunner.class)
#PrepareForTest(android.util.Log.class)
public class LoggerUnitTest {
#Test
public void testLog() throws Exception
{
PowerMockito.mockStatic(Log.class); // when(Log.e(anyString(), anyString())).thenReturn(1);
Logger.log("test", "test");
PowerMockito.verifyStatic(times(1));
Log.e(anyString(), anyString());
} }
For the RobolectricGradleTestRunner, the following incantation would have exposed your logging:
ShadowLog.stream = System.out
Robolectric does not print the Android system logging by default.
It's also worth noting that the RobolectricGradleTestRunner has been deprecated in favor of the fully operational RobolectricTestRunner (The above assignment is still effective)

Can't get JUnit tests to fail in Android Studio

I'm trying out Android development, but haven't come too far because I'm unable to get a test case to fail.
I have the following test case in the androidTest folder:
package com.example.aaronf.myapplication;
import android.test.*;
public class ToDoListTest extends AndroidTestCase {
private void newToDoListHasNoItems() {
assertEquals(new ToDoList().length, 0);
}
private void addingToDoGivesLengthOfOne() {
ToDoList toDoList = new ToDoList();
toDoList.add(new ToDo());
assertEquals(toDoList.length, 1);
}
public void runTests() {
newToDoListHasNoItems();
addingToDoGivesLengthOfOne();
}
public ToDoListTest() {
super();
runTests();
}
}
The ToDoList class looks like:
package com.example.aaronf.myapplication;
public class ToDoList {
public int length = 0;
public void add(ToDo toDo) {
}
}
It seems like it should fail on addingToDoGivesLengthOfOne(), but I get a green bar.
EDIT
I should add that adding #Test annotations to the methods generates a symbol not found error.
EDIT
I visited the suggested post My Junit test doesn't run. However, there is a difference with my problem. My methods used to have the test prefix, but this didn't affect the outcome. Also, the #Test annotation, as I mentioned before, is flagged with an error: "Cannot resolve symbol Test".
The problem was that my Test Artifact was set to Android Instrumentation Tests instead of Unit Tests. Since my unit tests were being added to the Android Instrumentation group, the unit testing stuff wasn't being recognized.

Android Espresso black-box testing

Does anyone try to do black-box testing with Android Espresso?
Could anyone provides me with some simple example?
I had tried some example before, but failed every time!
Example, I had tried this one:
public class ApplicationTest extends ActivityInstrumentationTestCase2
{
private static final String ACTIVITY_CLASSNAME = "com.example.kai_yu.blackboxtest";
private static Class launchActivityClass;
static
{
try
{
launchActivityClass = Class.forName(ACTIVITY_CLASSNAME);
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
public ApplicationTest()
{
super(launchActivityClass);
}
#Test
public void testClick()
{
}
}
But Android Studio said:
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.kai_yu.blackboxtest"
com.example.kai_yu.blackboxtest is applicationId which is another installed application on my phone
Thank you!
Espresso can only run as part of an instrumentation test.
Instrumentation tests can only act upon the app under test ( i.e. the target of the instrumentation ).
UIAutomator might be better for your use case.
https://developer.android.com/tools/testing-support-library/index.html#UIAutomator
In Espresso docs you would find this line:
While it can be used for black-box testing, Espresso's full power is unlocked by those who are familiar with the code base under test."
For that reason Espresso testing is called by gray-box testing.
If you're not familiar with programming in Java or Android, or you want just to write black-box testing in the clearest way as possible try to learn instead of Espresso this framework
Calabash-iOS and Calabash-Android are the underlying low-level libraries that empower the Cucumber tool to run automated functional tests on Android...
Website: https://calaba.sh/
GitHub: https://github.com/calabash
Here would you find how and why to start using this framework:
http://blog.teddyhyde.com/2013/11/04/a-better-way-to-test-android-applications-using-calabash/
#RunWith(AndroidJUnit4.class)
#LargeTest
public class EspressoTest1 extends ActivityInstrumentationTestCase2<MainActivity>{
public EspressoTest1() {
super(MainActivity.class);
}
#Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
}
#Test
public void test1ChatId() {
getActivity();
onView(withId(R.id.anuja)).check(matches(isDisplayed()));
}
#After public void tearDown() throws Exception {
super.tearDown();
}
}
There are two ways to write Espresso Test case one is as per shown above
The Examples are taken from this blog
http://qaautomated.blogspot.in/p/blog-page.html
Where you can find details of hot to run the espresso test case in detail.

Android - ActivityUnitTestCase - Tests Always Pass

I am using Android Studio to try and test my activity. Here is the basic code:
public class MyActivityTest extends ActivityUnitTestCase<MyActivity> {
public MyActivityTest() {
super(MyActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
}
#SmallTest
public void testSomething() {
Assert.assertNotNull("something is null", null);
}
}
I would expect that this test case fails. Everything I try passes though. This seems like a strange question, but how can I make my test case fail? What am I doing wrong?
I managed to get this working, sort of. I found this on a bug report:
We are in the process of deprecating ActivityUnitTestCase. We recommend to move business logic to a separate class and unit test it with gradle unit test support (mockable android.jar).
So I extended ActivityInstrumentationTestCase2 instead and ran the test as an Instrumentation Test rather than a Unit Test. That worked. Here is basically what I have now:
public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity> {
public MyActivityTest() {
super(MyActivity.class);
}
public void testSomething() throws Exception {
//test goes here
Assert.assertEquals(message, expectedObject, actualObject);
}
}
I'm still not sure why I was seeing the behavior I was earlier, but at least I can test now. Here is a screenshot of my Test Build Configuration:

Categories

Resources