This may be a simple answer.
1) Create a jar file with this code:
package com.myCompany.base;
public class Dex1 {
public String getTerm1() {
return "Term 1";
}
}
This is compiled to Dex1.jar using NetBeans.
2) Created a 'Hello world' android application in Eclipse. Add the code for Dex2 that extends Dex1. Copy and add Dex1.jar to the java build path.
package com.myCompany;
import com.myCompany.base.Dex1;
public class Dex2 extends Dex1 {
public String getTerm2() {
return getTerm1() + " Term 2";
}
}
in my onCreate() call:
editText.setText(dex2.getTerm2());
Everything works Great! I get the correct string displayed on the android screen. Yea!
Now the problem starts:
3) Create a jUnit 3 test case using Eclipse command File -> New -> Project -> Android Text Project command and add the code:
package com.myCompany.test;
import junit.framework.TestCase;
import com.myCompany.Dex2;
public class Dex2Test extends TestCase {
protected void setUp() throws Exception {
super.setUp();
dex2 = new Dex2();
}
protected void tearDown() throws Exception {
super.tearDown();
}
Dex2 dex2;
public void testGetTerm2() {
/*line 21 */ assertEquals("Term 1 Term 2", dex2.getTerm2());
}
public void testGetTerm1() {
/* line 25 */ assertEquals("Term 1", dex2.getTerm1());
}
}
On Line 25 the compiler gives a 'method undefined' error for getTerm1(). I don't understand why this is an error?
I tried to add the Dex1.jar to the java Build path of the test project, it compiles but we receive a run time error 'NoClassDefFoundError'. Yuch!
More Information 16Mar2012
I set this up using Plan Java classes, same jar file, to remove Android and it worked. This makes me conclude there must be some anomaly in Android/DalvikVM (aka DavrosVM).
More Information 16Mar2012 End
Am I missing something?
Is the jar file built incorrectly (didn't think that was possible)?
Am I importing the jar file incorrectly?
Is it just crazy to expect to import and override a class in a jar file?
Thank you for reading, please reply.
Fish
Take a look at Android Testing: External libraries which I guess have the solution to your problem.
What you may be doing wrong is not exporting your library in Order and Export under Java Build Path.
Related
I'm running some tests with Roboletric, but I came across a issue that I can't solve.
When I run the test, the following error appears with the "AndroidManifest":
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).
No such manifest file: .\AndroidManifest.xml
I've tried these solutions that failed:
#Config (manifest = Config.DEFAULT_MANIFEST_NAME)
#Config(manifest = Config.NONE, constants = BuildConfig.class, sdk = 26)
#Config( constants = BuildConfig.class, manifest="src/main/AndroidManifest.xml", sdk = 26 )
And the other error during execution is:
android.content.res.Resources$NotFoundException: Unable to find
resource ID #0x7f09001b in packages [android, org.robolectric.default]
...
at
com.example.robertoassad.alltestsmerge.MainActivity.onCreate(MainActivity.java:52)
This line that have the error is the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Specifically in: setContentView(R.layout.activity_main);
For me I didn't see sense in this issue ...
DETAILS:
The test class is on the folder: app\src\test\java\com\example\robertoassad
The test is:
#RunWith( RobolectricTestRunner.class)
public class Roboletric {
#Test
public void clickingLogin_shouldStartLoginActivity() {
MainActivity activity = Robolectric.setupActivity(MainActivity.class);
activity.findViewById(R.id.button2).performClick();
Intent expectedIntent = new Intent(activity, SecondActivity.class);
Intent actual = ShadowApplication.getInstance().getNextStartedActivity();
assertEquals(expectedIntent.getComponent(), actual.getComponent());
}
}
I had a similar problem to the one you face. The post by jongerrish on the Robolectric GitHub Issue about this resolved the problem for me.
The aspect of the answer that worked for me was to add a testOptions block in my module's build.gradle file:
testOptions {
unitTests {
includeAndroidResources = true
}
}
After adding this block my tests were able to run and access String resources.
This problem bug me for some time, and here is my note in my test code.
About manifest location
With Gradle build system, Robolectric looks for AndroidManifest.xml in the following order.
Java resource folder
build/intermediates/manifests/[full or fast-start]/[build-type]
So it is a common mistake to specify the location of AndroidManifest.xml according to source code folder organization (e.g. src/main/AndroidManifest.xml) . The specified AndroidManifest.xml location affect how Robolectric look for merged resources as well. So if some resource is not found in test, it is probably due to incorrect setting of AndroidManifest.xml location.
That said, the Android Gradle plugin merge the AndroidManifest.xml and put the result under the above mentioned intermediates directory. So the content of src/main/AndroidManifest.xml affect the test result.
So if you want to specify manifest option in #Config, just use #Config(manifest=“AndroidManifest.xml”) should probably be fine. If you want to use an alternate AndroidManifest.xml, put it in Java resources folder, and specify #Config according to the relative path in resources folder.
I was also facing same problem while testing my library module from app. Now my Receievers and Service are in my library, so to test those , i had to implement custom Test Class, so Roboelectric can point to my library manifest and not the app manifest :
import android.os.Build;
import org.junit.runners.model.InitializationError;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.res.Fs;
import java.io.File;
import java.io.IOException;
public class RobolectricGradleTestRunner extends RobolectricTestRunner {
private static final String PROJECT_DIR =
"C:/MyProject/";
private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC =
Build.VERSION_CODES.JELLY_BEAN_MR2;
public RobolectricGradleTestRunner(final Class<?> testClass) throws Exception {
super(testClass);
}
private static AndroidManifest getAndroidManifest() {
String manifestPath = PROJECT_DIR+"/src/main/AndroidManifest.xml";
String resPath = PROJECT_DIR+"/src/main/res";
String assetPath = PROJECT_DIR+"/src/main/assets";
System.out.print("manifest path: "+manifestPath);
System.out.print("resPath path: "+resPath);
System.out.print("assetPath path: "+assetPath);
return new AndroidManifest(
Fs.fileFromPath(manifestPath), Fs.fileFromPath(resPath), Fs.fileFromPath(assetPath)) {
#Override public int getTargetSdkVersion() {
return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
}
};
}
private static String getProjectDirectory() {
String path = "";
try {
File file = new File("..");
path = file.getCanonicalPath();
path = path + "/app/";
} catch (IOException ex) {}
return path;
}
#Override public AndroidManifest getAppManifest(Config config) {
return getAndroidManifest();
}
}
and use it in your test class like :
#RunWith(RobolectricGradleTestRunner.class)
public class MyClassChangeTest {
}
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)
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.
I have three Android projects: BaseLibProject, MainLibProject, AppProject.
The relationship of these three Android projects is that:
The BaseLibProject is a library project used by MainLibProject.
The MainLibProject uses BaseLibProject as library project, and generates MainLib.jar(use maven build)
The generated MainLib.jar is added to AppProject's libs/ folder & also added to the build path of AppProject.
NEXT:
A simple class in BaseLibProject :
public class BaseLibClass {
public static String doBaseTask() {
Log.i("MyLog", "doBaseTask..."); //I can't see this log
return "Result from Base!";
}
}
A simple class in MainLibProject which defined a function invokes the function in BaseLibProject:
public class MainLibClass {
public static void doMainTask() {
Log.i("MyLog", "doMainTask..."); //I can see this log in logcat
String result = BaseLibClass.doBaseTask();
Log.i("MyLog", "result = " + result); //I can see the result log
}
}
Finally, in my AppProject I simply call above function of MainLibProject (remember I have MainLib.jar):
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MainLibClass.doMainTask();
}
}
I started logcat with command adb logcat -s MyLog:* . When I run my AppProject application, logcat displays
I/MyLog(2039): doMainTask...
I/MyLog(2039): result = Result from Base!
According to above log, the code in BaseLibProject is running (because I got result from BaseLibClass), but it doesn't display any logs from BaseLibProject, why???
(I have googled on internect, someone got similar issue fixed by restarting eclipse, but in my case, it doesn't help. Besides, I am checking logs from terminal NOT from eclipse.)
Ok, finally, I fixed the problem.
The reason is that in BaseLibProject pom.xml, I defined <packaging>apk</packaging>, while in MainLibProject pom.xml, when I define the dependency of BaseLibProject, I didn't specify the <type> of the artifact.
After I changed BaseLibProject's pom.xml to <packagin>apklib</packaging> and in MainLibProject's pom.xml specified the dependency of BaseLibProject with <type>apklib</type> . I am able to see the logs in BaseLibProject.
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?