How to abstract Robotium Setup to run multiple test files - java

In a Blackbox test environment I would need to include CODE 1 and end with CODE 2 to perform a test by running Android JUnit Test (as explained from the Robotium site):
CODE 1:
public class ConnectApp extends ActivityInstrumentationTestCase2 {
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME="com.example.android.notepad.NotesList";
private static Class<?> launcherActivityClass;
private Solo solo;
static {
try { launcherActivityClass=Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); }
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
public ConnectApp() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
this.solo = new Solo(getInstrumentation(), getActivity());
}
CODE 2:
public void testNumberOne() { … }
public void testNumberTwo() { … }
}
However, I would like to abstract CODE 1 of the code ( which includes getInstrumentation() and getAcitvity()) so that I can simply call them in a separate test file and then run CODE 2 . This is because I want to have tests in separate files and don't want to keep adding the same amount of CODE 1 code but just call a method/constructor to initiate the process.
Is there a way to do this? Thank you in advance.

yes there is a way to do this. What you will need to do is create an empty test class such as:
public class TestTemplate extends ActivityInstrumentationTestCase2 {
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME="com.example.android.notepad.NotesList";
private static Class<?> launcherActivityClass;
private Solo solo;
static {
try { launcherActivityClass=Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); }
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
public ConnectApp() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
super.setUp();//I added this line in, you need it otherwise things might go wrong
this.solo = new Solo(getInstrumentation(), getActivity());
}
public Solo getSolo(){
return solo;
}
}
Then for every test class you want in the future instead of extending ActivityInstrumentationTestCase2 you will extend TestTemplate.
for example:
public class ActualTest extends TestTemplate {
public ActualTest() throws ClassNotFoundException {
super();
}
public void setUp() throws Exception {
super.setUp();
//anything specific to setting up for this test
}
public void testNumberOne() { … }
public void testNumberTwo() { … }
}

Related

How to undo/reset PowerMockito.mockStatic?

Assuming I have the following classes
public class StaticClass {
public static void staticMethod() throws SomeException {
System.out.println("staticMethod");
}
private StaticClass() {
}
}
and
public class SomeClass {
public void someMethod() {
try {
StaticClass.staticMethod();
}catch(SomeException ex) {
System.out.println("SomeException occurred");
return;
}
System.out.println("SomeException didn't occur");
}
}
which I'm testing with
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticClass.class)
public class SomeClassTest {
#Test
public void testStaticMethod() throws Exception {
mockStatic(StaticClass.class);
doThrow(new SomeException("unimportant message")).when(StaticClass.class,
"staticMethod");
//test something where exception is needed
SomeClass instance = new SomeClass();
try {
instance.someMethod();
fail("IllegalStateException expected");
}catch(IllegalStateException expected) {
}
//now test something where exception isn't needed
instance.someMethod();
}
}
How can I undo the static mocking/the configuration to throw SomeException so that I can test the code after the try-catch block in the second instance.someMethod()?
PowerMock: How to unmock a method? doesn't apply because there's no mock reference to pass to Mockito.reset and passing StaticClass causes java.lang.ClassCastException: java.lang.Class cannot be cast to org.mockito.internal.creation.bytebuddy.MockAccess.
SomeException simply extends Exception.
A SSCCE is provided at https://gitlab.com/krichter/powermock-undo-statik-mocking.
I'm using PowerMock 1.7.3.
My opinion, but in general a unit test should exercise a single code path. (I think of this as applying single responsibility to a test method.)
Bu my suggestion about splitting the tests does solve the problem. I don't know the details, but #PrepareForTest provides a fresh StaticClass for each test.
These separate tests work:
#Test
public void testStaticMethodWhenSomethingUnexpectedHappens() throws Exception {
mockStatic(StaticClass.class);
// changed exception type
doThrow(new IllegalStateException("unimportant message")).when(StaticClass.class, "staticMethod");
SomeClass instance = new SomeClass();
try {
instance.someMethod();
fail("IllegalStateException expected");
} catch (IllegalStateException expected) {
}
// added verification
verifyStaticMethodWasInvokedOneTime();
}
#Test
public void testStaticMethodHappyPath() throws Exception {
mockStatic(StaticClass.class);
doNothing().when(StaticClass.class, "staticMethod");
SomeClass instance = new SomeClass();
instance.someMethod();
// added verification
verifyStaticMethodWasInvokedOneTime();
}
private void verifyStaticMethodWasInvokedOneTime() throws SomeException {
verifyStatic(StaticClass.class);
StaticClass.staticMethod();
}
For anyone wondering how to reset PowerMocks e.x. for those pesky private static final loggers...
There was an issue (see Karl's comment in accepted solution) addressing it and the solution was to use #PrepareForTest in the method level.
so in your test method you need the annotation
/*
* Test for MyClass.java which uses a private static final logger
*/
public class MyStaticMockTest {
static final Logger logger = PowerMockito.mock(Logger.class);
#BeforeClass
public static void setup() {
PowerMockito.mockStatic(LoggerFactory.class);
PowerMockito.when(LoggerFactory.getLogger(MyClass.class))
.thenReturn(MyStaticMockTest.logger);
}
#Test
#PrepareForTest({LoggerFactory.class, Logger.class})
public void testit() {
MyClass mc = new MyClass();
mc.methodWithSomeLogging();
Mockito.verify(MyStaticMockTest.logger).info("some message");
}
#Test
#PrepareForTest({LoggerFactory.class, Logger.class})
public void testit() {
MyClass mc = new MyClass();
mc.anotherMethodWithSomeLoggingButUsingSameMessage();
//Method will pass and not complain about info being called 2x
Mockito.verify(MyStaticMockTest.logger, Mockito.times(1)).info("some message");
}
}
if you want every single method reset, just put the #PrepareForTest decorator on the class instead of the method

Using jmockit to mock constructor that throws error: NoClassDefFoundError

Jmockit is very powerful, but sometimes I cannot understand what it does behind the scene, so I have a question regarding jmockit. Hopefully the more experienced programmers on here could help shine some light on this situation :)
I have the following two classes in two separate files:
public class SmallClass {
String a;
SmallClass(String arg) throws Exception {
a = arg;
}
public String getString() {
return a;
}
}
And
public class BigClass {
private static final SmallClass smallClass;
static {
try {
smallClass = new SmallClass("dummy");
} catch (Exception e) {
throw new IllegalStateException("Could not initialized", e);
}
}
public static String getString() {
return smallClass.getString();
}
}
Now, I have a class to test BigClass:
public class BigClassTest {
#Test
public void testGet() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
}
}
If I run each of these independently, then they each passes. But if I run the whole test file, then the first test fails with:
java.lang.NoClassDefFoundError: Could not initialize class BigClass
I also tried tearing down the mock after each test like this, but it doesn't help:
public class BigClassTest {
MockUp<SmallClass> smallClassMockUp;
#Test
public void testGet() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
smallClassMockUp.tearDown();
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
smallClassMockUp.tearDown();
}
}
Any help would be appreciated. Thank you in advance!
The occurrence of NoClassDefFoundError, in a case like this, is not because the class wasn't found by the JVM (it was), but because its static initialization has failed (by throwing an exception or error from the execution of a static initializer). Once this happens, the class is left in an invalid/uninitialized state and cannot be used in the same JVM instance anymore.
For reference, see the "Initialization of classes and interfaces" section in the JLS.
Also, note that the order in which tests execute is not necessarily the textual order they appear in the test class. Here, testException (the second test) runs first. So, when testGet runs, the class is invalid and the JVM throws the error.

ThreadWeaver always throws IllegalArgumentException

I am trying to use Google ThreadWeaver to write a unit test for concurrent code. No matter what I do, I will get an IllegalArgumentException. I am still working with an example, but even that does not work. This is what I tried:
public class ExampleTest {
public static class ExampleMain implements MainRunnable<Example> {
private Example example;
#Override
public Class<Example> getClassUnderTest() {
return Example.class;
}
#Override
public String getMethodName() {
return null;
}
#Override
public Method getMethod() throws NoSuchMethodException {
return null;
}
#Override
public void initialize() throws Exception {
example = new Example();
}
#Override
public Example getMainObject() {
return example;
}
#Override
public void terminate() throws Exception {
}
#Override
public void run() throws Exception {
example.test("second");
}
}
public static class ExampleSecondary implements SecondaryRunnable<Example, ExampleMain> {
private ExampleMain exampleMain;
#Override
public void initialize(ExampleMain main) throws Exception {
exampleMain = main;
}
#Override
public void terminate() throws Exception {
}
#Override
public boolean canBlock() {
return false;
}
#Override
public void run() throws Exception {
exampleMain.getMainObject().test("main");
}
}
public static class Example {
private List<String> list = new ArrayList<String>();
public String test(String s) {
System.out.println("1" + s);
list.add(s);
System.out.println("2" + s);
return list.get(0);
}
}
#Test
public void testThreadWeaver() throws Exception {
ClassInstrumentation instrumentation = Instrumentation.getClassInstrumentation(Example.class);
Method tested = Example.class.getDeclaredMethod("test", String.class);
Method breakpoint = List.class.getDeclaredMethod("add", Object.class);
CodePosition codePosition = instrumentation.afterCall(tested, breakpoint);
InterleavedRunner.interleave(new ExampleMain(), new ExampleSecondary(), Arrays.asList(codePosition)).throwExceptionsIfAny();
}
}
The stack trace says:
java.lang.IllegalArgumentException: Class Example is not instrumented
at
com.google.testing.threadtester.CallLoggerFactory.getClassInstrumentation(CallLoggerFactory.java:108)
at
com.google.testing.threadtester.Instrumentation.getClassInstrumentation(Instrumentation.java:65)
at MyTest.testThreadWeaver(MyTest.java:92
I followed the instructions at the official Google code webpage, but it does not seem to work. Any ideas?
ThreadWeaver needs to instrument your classes in order to add breakpoints to your methods. Therefore, you cannot run the tests with JUnit directly but you must run your test from a specific test runner. For your case this would be ThreadedTestRunner. The actual test methods must then be annotated with #ThreadedTest instead of #Test. This should work:
#Test
public void startTest() throws Exception {
new ThreadedTestRunner().runTests(getClass(), Example.class);
}
#ThreadedTest
public void testThreadWeaver() throws Exception {
// here comes your test
}

organizing unittests in java/junit for testing classes with common api

I am implementing some elementary sorting algorithms (for the purpose of learning) ,and want to write unittests for them .All the sorting programs have the following common api
...
public static void sort(Comparable[] a);
...
public static boolean isSorted(Comparable[] a);
...
public static boolean isSorted(Comparable[] a),int from ,int to;
...
So,I wrote the following tests for testing the isSorted() method in SelectionSort
public class SelectionSortTests {
String[] a ;
#After
public void tearDown() throws Exception {
a = null;
}
#Test
public void arraySortedSingleElement(){
a = new String[]{"A"};
Assert.assertTrue(SelectionSort.isSorted(a));
}
#Test
public void arraySortedDistinctElements(){
a = new String[]{"A","B","C","D"};
Assert.assertTrue(SelectionSort.isSorted(a));
}
#Test
public void arrayNotSorted(){
a = new String[]{"A","B","C","B"};
Assert.assertFalse(SelectionSort.isSorted(a));
}
...
}
Now I feel that if I were to write tests for say InsertionSort,ShellSort etc ,they would look the same..Only the name of the class under test will change..
So,how should I organize the tests? Is a suite the answer or can I do better using reflection - may be write a driver program to which I can add a list of names of classes to be tested, and the driver invokes runs the common unit tests by passing the classname to it..
I realize this is a common situation..would like to know how this can be handled without spittle or cellotape
UPDATE:
thanks #BevinQ and #Matthew Farwell ,I tried to solve this using Parameterized unit tests.
Used reflection to call the static method ..
Seems to work :) though I think it can still be refactored to avoid duplicate code
#RunWith(Parameterized.class)
public class ParameterizedSortTests {
private Class classToTest;
private Method methodToTest;
public ParameterizedSortTests(String packageName,String classToTest) {
super();
try {
this.classToTest = Class.forName(packageName+"."+classToTest);
} catch (ClassNotFoundException e) {
System.out.println("failed to get class!!");
e.printStackTrace();
}
}
//method return collection of class names to be tested
#Parameterized.Parameters
public static List<Object[]> classesToTest(){
return Arrays.asList(new Object[][]{
{"elemsorts","SelectionSort"} ,
{"elemsorts","InsertionSort"}
});
}
public void setMethod(String method,Class...args){
try {
this.methodToTest = this.classToTest.getMethod(method, args);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
#Test
public void arrayIsSorted(){
setMethod("isSorted",Comparable[].class);
String[] a = new String[]{"A","B","C","D"};
Boolean arraySorted = null;
try {
arraySorted = (Boolean)this.methodToTest.invoke(null, new Object[]{a});
System.out.println(this.methodToTest+"returned :"+arraySorted);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Assert.assertTrue(arraySorted);
}
#Test
public void arrayIsNotSorted(){
setMethod("isSorted",Comparable[].class);
String[] a = new String[]{"A","B","C","B"};
Boolean arraySorted = null;
try {
arraySorted = (Boolean)this.methodToTest.invoke(null, new Object[]{a});
System.out.println(this.methodToTest+"returned :"+arraySorted);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//System.out.println("arraySorted="+arraySorted);
Assert.assertFalse(arraySorted);
}
}
for interface
public abstract class AbstractSortTests {
String[] a ;
#After
public void tearDown() throws Exception {
a = null;
}
protected abstract Sorter getSorter();
#Test
public void arraySortedSingleElement(){
a = new String[]{"A"};
Assert.assertTrue(getSorter().isSorted(a));
}
#Test
public void arraySortedDistinctElements(){
a = new String[]{"A","B","C","D"};
Assert.assertTrue(getSorter.isSorted(a));
}
...
}
public class SelectionSortTests extends AbstractSortTests {
protected Sorter getSorter(){
return SelectionSort.getInstance();
}
}
public class QuickSortTests extends AbstractSortTests {
protected Sorter getSorter(){
return QuickSort.getInstance();
}
}
using reflection it is a bit messier but still do-able. I have not tested this code so might have
a couple of bugs, but have used this method in the past. Using interfaces would be the preferred method in 99% of cases.
public abstract class AbstractSortTests {
String[] a ;
#After
public void tearDown() throws Exception {
a = null;
}
protected abstract Sorter getSorter();
#Test
public void arraySortedSingleElement() throws Exception{
a = new String[]{"A"};
Assert.assertTrue(executeMethod(getSorterClass(), "isSorted", a);
}
#Test
public void arraySortedDistinctElements() throws Exception{
a = new String[]{"A","B","C","D"};
Assert.assertTrue(executeMethod(getSorterClass(), "isSorted", a);
}
private void executeMethod(Class<?> sortClass, String methodName, String[] values) throws Exception{
return sortClass.getDeclaredMethod(methodName, new Class[]{String[].class}).invoke(null, new Object[]{values});
}
...
}
public class SelectionSortTests extends AbstractSortTests {
protected Class<?> getSorterClass(){
return SelectionSort.class;
}
}
As #BevynQ says, you'll make life a lot easier for yourself if you make your methods non-static, and you implement an interface (called Sorter below). The you can easily use Parameterized. This is a very quick example of how to use it, (untested, uncompiled)
#RunWith(Parameterized.class)
public class SorterTest {
#Parameters
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] {
{ new SelectionSort() },
{ new BubbleSort() }
});
}
private final Sorter sorter
public SorterTest(Sorter sorter) {
this.sorter = sorter;
}
#Test
public void arraySortedSingleElement(){
String[] a = new String[]{"A"};
Assert.assertTrue(sorter.isSorted(a));
}
#Test
public void arraySortedDistinctElements(){
String[] a = new String[]{"A","B","C","D"};
Assert.assertTrue(sorter.isSorted(a));
}
#Test
public void arrayNotSorted(){
String[] a = new String[]{"A","B","C","B"};
Assert.assertFalse(sorter.isSorted(a));
}
}
why not something like this?
#Test
public void arraySortedDistinctElements(){
a = new String[]{"A","B","C","D"};
Assert.assertTrue(SelectionSort.isSorted(a));
Assert.assertTrue(InsertionSort.isSorted(a));
Assert.assertTrue(QuickSort.isSorted(a));
}
I don't think you have more than 10 different sortings to test. so it should be good.
otherway, you can declare all Sorting classes in Array and load using Class properties.

how to call android activity from standard java code?

This is my sample test project which tests android calculator using robotium.
I want to create jar file of this project but while creating it, it shows error as below:
"Error: Could not find or load main class TestMain".
I think its showing this error becouse there is no main class in that i.e. it couldn't find "public static void main(String args[])". what should i do to overcome this problem?
package com.testcalculator;
import com.jayway.android.robotium.solo.Solo;
import android.test.ActivityInstrumentationTestCase2;
#SuppressWarnings("unchecked")
public class TestCal extends ActivityInstrumentationTestCase2
{
private static final String TARGET_PACKAGE_ID="com.calculator";
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME="com.calculator.Main";
private static Class launcherActivityClass;
static
{
try
{
launcherActivityClass=Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
public TestCal()throws ClassNotFoundException
{
super(launcherActivityClass);
}
private Solo solo;
#Override
protected void setUp() throws Exception
{
solo = new Solo(getInstrumentation(),getActivity());
}
public void testDisplayBlackBox()
{
solo.enterText(0, "10");
solo.enterText(1, "20");
solo.clickOnButton("Multiply");
assertTrue(solo.searchText("200"));
}
#Override
public void tearDown() throws Exception
{
solo.finishOpenedActivities();
}
}

Categories