How to inject a method invocation into another method in android - java

I have a class with,
a field called something,
a setter method called setSomething, and,
a method called onChange which should be called every time something is changed.
I want to be able to freely add more fields and have the same behavior for all of them.
I don't want to manually call onChange because,
A lot of boilerplate,
Code will be written in Kotlin so I don't want to write setter functions at all.
The ideal solution I've been able to think of has been to somehow inject the onChange call right before the return for each setter method in compile time.
I've looked at annotation processing, but apparently classes aren't actually compiled at that stage, so I'd have to generate the entire class all over again? I don't exactly understand this.
The other option seems to be writing a gradle plugin that will find the relevant class(es) and modify their bytecode.
I've actually started work on this as a pure Java project (gradle plugin is semi-done) and have been able to find the classes and inject the method call. Can't seem to successfully write the results to a class file though.
Here's what I have (using BCEL):
public class StateStoreInjector {
public static void main(String[] args) {
// Find all classes that extends StateStore
Reflections reflections = new Reflections("tr.xip.statestore");
Set<Class<? extends StateStore>> classes = reflections.getSubTypesOf(StateStore.class);
for (Class c : classes) {
try {
JavaClass clazz = Repository.lookupClass(c.getName());
JavaClass superClazz = Repository.lookupClass(StateStore.class.getName());
if (Repository.instanceOf(clazz, superClazz)) {
injectInClass(clazz, superClazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private static void injectInClass(JavaClass clazz, JavaClass superClazz) {
ClassGen classGen = new ClassGen(clazz);
ConstantPoolGen cp = classGen.getConstantPool();
// Find the onChange method
Method onChangeMethod = null;
for (Method m : superClazz.getMethods()) {
if (m.getName().equals("onChange")) {
onChangeMethod = m;
}
}
if (onChangeMethod == null) {
throw new RuntimeException("onChange method not found");
}
ClassGen superClassGen = new ClassGen(superClazz);
ConstantPoolGen superCp = superClassGen.getConstantPool();
// Add onChange method ref to the class ConstantPool
MethodGen onChangeMethodGen = new MethodGen(onChangeMethod, superClassGen.getClassName(), superCp);
cp.addMethodref(onChangeMethodGen);
// Loop through all methods to inject method invocations if applicable
for (Method m : clazz.getMethods()) {
// Skip methods with names shorter than 3 chars - we're looking for setters and setters would be min 4 chars
if (m.getName().length() < 3) continue;
// Check if the method actually starts with the keyword "set"
boolean isSetMethod = m.getName().substring(0, 3).toUpperCase().equals("SET");
// Get method name without the "set" keyword
String methodName = m.getName().substring(3, m.getName().length());
// Check that we actually have a field set by this setter - that this setter is "valid"
boolean fieldWithSameNameExists = false;
for (Field f : clazz.getFields()) {
if (f.getName().toUpperCase().equals(methodName.toUpperCase())) {
fieldWithSameNameExists = true;
break;
}
}
// Proceed with injection if criteria match
Method newMethod = null;
if (isSetMethod && fieldWithSameNameExists) {
newMethod = injectInMethod(m, onChangeMethodGen, classGen, cp);
}
// Injection returned. Do we have a new/modified method? Yes? Update and write class.
if (newMethod != null) {
classGen.removeMethod(m);
classGen.addMethod(newMethod);
classGen.update();
try {
String packageName = clazz.getPackageName().replace(".", "/");
String className = clazz.getClassName();
className = className.substring(className.lastIndexOf(".") + 1, className.length());
clazz.dump(packageName + "/" + className + "Edited.class");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static Method injectInMethod(Method m, MethodGen onChangeMethodGen, ClassGen cg, ConstantPoolGen cp) {
MethodGen methodGen = new MethodGen(m, cg.getClassName(), cp);
InstructionList il = methodGen.getInstructionList();
println(il.toString() + "pre insert ^");
// Find the "return" instruction
Instruction returnInstruction = null;
for (Instruction i : il.getInstructions()) {
if (i.getOpcode() == 177) returnInstruction = i;
}
// If found, insert onChange invocation instruction before the return instruction
if (returnInstruction != null) {
int index = cp.lookupMethodref(onChangeMethodGen); // Find the index of the onChange method in the CP
il.insert(returnInstruction, new INVOKEVIRTUAL(index)); // Insert the new instruction
println(il.toString() + "post insert ^");
il.setPositions(); // Fix positions
println(il.toString() + "post set pos ^");
il.update();
methodGen.update();
return methodGen.getMethod();
}
return null;
}
private static void println(String message) {
System.out.println(message);
}
}
Input Java class:
public class DummyStateStore extends StateStore {
private int id = 4321;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
Parent Store class:
public class StateStore {
public void onChange() {
// notifies all subscribers
}
}
Output (decompiled) class file:
public class DummyStateStore extends StateStore {
private int id = 4321;
public DummyStateStore() {
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
Log output:
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: return[177](1)
pre insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
-1: invokevirtual[182](3) 26
5: return[177](1)
post insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: invokevirtual[182](3) 26
8: return[177](1)
post set pos ^
(I checked the index 26 by debugging the code and it is the correct index in the CP)
Now, the questions are:
Why can't the invocation be seen in the decompiled code but it seems to be added to the instructions list? What am I missing?
Where would I be exporting the modified class files in an android build for them to be included in the final apk?

You're trying to use reflection, but there should be no need to do so with Kotlin as you can create higher order functions (functions that take functions as inputs).
You could do something like:
class ChangeableType<T>(private var value: T, private val onChange: () -> Unit) {
fun set(value: T) {
this.value = value
this.onChange.invoke()
}
}
class MyRandomClass() {
val something = ChangeableType(0, { System.print("Something new value: $value") })
val anotherThing = ChangeableType("String", { System.print("Another thing new value: $value") })
}
class ConsumingClass {
val myRandomClass = MyRandomClass()
fun update() {
myRandomClass.apply {
something.set(1)
anotherThing.set("Hello World")
}
}
}

Related

Writing a JUnit Rule: Description doesn't contain my annotation

I'm trying to write a simple JUnit Rule implementation which reruns a test case a given amount of times if not successful.
It works fine as such, but I'd like to make it configurable per method with a custom annotation I attach to the method.
Here's my rule implementation:
public class Retry implements TestRule {
private int retryCount = 10;
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
RetryCount annotation = description.getAnnotation(RetryCount.class);
// Problem is here, the annotation is always null!
int retries = (annotation != null) ? annotation.retries() : retryCount;
// keep track of the last failure to include it in our failure later
AssertionError lastFailure = null;
for (int i = 0; i < retries; i++) {
try {
// call wrapped statement and return if successful
base.evaluate();
return;
} catch (AssertionError err) {
lastFailure = err;
}
}
// give meaningful message and include last failure for the
// error trace
throw new AssertionError("Gave up after " + retries + " tries", lastFailure);
}
};
}
// the annotation for method-based retries
public static #interface RetryCount {
public int retries() default 1;
}
}
In the line I commented, I don't get the annotation I attach to the method:
public class UnreliableServiceUnitTest {
private UnreliableService sut = new UnreliableService();
#Rule
public Retry retry = new Retry();
#Test
#RetryCount(retries=5) // here it is
public void worksSometimes() {
boolean worked = sut.workSometimes();
assertThat(worked, is(true));
}
}
If I debug into the Rule, the Description annotation list contains the #Test annotation but not the #RetryCount. I also tried adding a #Deprecated which will also get added.
Any idea why?
For completeness, this is the sample SUT:
public class UnreliableService {
private static Random RANDOM = new Random();
// needs at least two calls
private static int COUNTER = RANDOM.nextInt(8) + 2;
public boolean workSometimes() {
if (--COUNTER == 0) {
COUNTER = RANDOM.nextInt(8) + 2;
return true;
}
return false;
}
}
The #Test annotation is a Runtime annotation. Your RetryCount is not defined like that. It should be so you can access it during runtime. Change your code to this:
// the annotation for method-based retries
#Retention(value=RUNTIME)
public static #interface RetryCount {
public int retries() default 1;
}
Using RetentionPolicy Runtime allows you to read the annotations reflectively. See here the Javadoc

Creating array of methods returning boolean and iterating through for-each loop

Okay so I have a batch of methods returning boolean values of true/false.
private void saveChangesOnEditButtonActionPerformed(java.awt.event.ActionEvent evt) {
updateMainTabsAccess();
updateUserPaymentTabPermissions();
updateUserRegistrationTabPermissions();
updateUserStudentsTabPermissions();
updateUserFacultyTabPermissions();
updateUserHomePermissions(); //saves any update made on existing user settings/permissions
updateUserInformation(); // sasve any update made on existing user information such as username
}
I would like to know if it's possible for me to check each of the methods' return value through a for-each loop.
I'm thinking of creating a private boolean isUpdateSuccessful() method.
Say like,
private boolean isUpdateSuccessful(){
Boolean a = updateMainTabsAccess();
Boolean b = updateUserPaymentTabPermissions();
//........so on....
Boolean result = (a && b &&...)
return result;
}
Problem is, I don't know if it's possible to put them in an arraylist or component array like
ArrayList<Boolean> listOfMethods = new ArrayList<Boolean>(method1,method2..);
So that I can then check each through a for-each loop
for(Boolean b:listOfMethods){
Boolean successful=true;
successful = (successful && b)
}
My questions are:
1.) How do I extract the return values of these methods and use the methods to initialize the Arraylist.
2.) Using for-each loop, is there any possibility of what I'm trying to do? I none, then what do you suggest I do?
I'd appreciate any answer or suggestion. I simply want to check if every method was successful. I thought of using ?1:0:
Thanks in advance.
If I am you, I would do this. Just a sample code:
private void saveChangesOnEditButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (updateMainTabsAccess()) {
if (updateUserPaymentTabPermissions()) {
if (updateUserRegistrationTabPermissions()) {
...
} else {
// error on update registration
}
} else {
// error on update payment
}
}
With the above style:
You don't execute other methods when the before one fails.
Can have detailed error messages for each error.
You need not to main a collection and iteration.
Why not use a Stream to check the results:
Stream.<Boolean>of(updateMainTabsAccess(),
updateUserPaymentTabPermissions(),
updateUserRegistrationTabPermissions(),
updateUserStudentsTabPermissions(),
updateUserFacultyTabPermissions(),
updateUserHomePermissions(),
updateUserInformation()).allMatch(b -> b);
this way you get rid of short circuit evaluation and also don't need to create method references for each method.
method references
List<Supplier<Boolean>> methods = Arrays.asList(this::updateMainTabsAccess,
this::updateUserPaymentTabPermissions,
...
);
for (Supplier<Boolean> supplier : methods) {
boolean methodResult = supplier.get();
...
}
This can hardly be considered an improvement though...
this will find all method in side your class which is return Boolean after automatically invoke method one by one and store response to successful variable
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class Test {
public static void main(String[] args) {
Test test = new Test();
Class c = test.getClass();
boolean successful = true;
for (Method method : c.getDeclaredMethods()) {
if (method.getReturnType().toString().equals("boolean")) {
try {
String mname = method.getName();
Object o = method.invoke(test, null);
System.out.format("%s() returned %b%n", mname, (Boolean) o);
successful = successful && (Boolean) o;
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println("final answer : " + successful);
}
public boolean a() {
return true;
}
public boolean b() {
return false;
}
public boolean c() {
return false;
}
}
Hope its help to you.
If you want every method to be executed and check if every method scucceded you could simply write
boolean success = updateMainTabsAccess() &
updateUserPaymentTabPermissions() &
updateUserRegistrationTabPermissions() &
updateUserStudentsTabPermissions() &
updateUserFacultyTabPermissions() &
updateUserHomePermissions() &
updateUserInformation();
You have already received some answers.
Fabian's is a good one if you are using java 8.
But to answer directly your points
1.) How do I extract the return values of these methods and use the methods to initialize the Arraylist.
ArrayList<Boolean> resultsList = new ArrayList<Boolean>();
resultsList.add(updateMainTabsAccess());
...
2.) Using for-each loop, is there any possibility of what I'm trying to do? I none, then what do you suggest I do?
boolean res = true;
for (Boolean singleResult : resultsList) {
res = res && singleResult;
}
Here is the old style way to acheive your goal when Lambdas weren't introduced by Java 8.
public class TestMethodsListCall {
public abstract class Checker {
public abstract boolean check();
}
public static void main(String[] args) {
new TestMethodsListCall();
}
public TestMethodsListCall() {
final TestMethodsListCall that = this;
List<Checker> checkers = Arrays.asList( //
new Checker() { public boolean check() { return that.methodA(); } }, //
new Checker() { public boolean check() { return that.methodB(); } } //
// , ...
);
boolean res = true;
for (Checker c : checkers) {
res = res & c.check();
if (!res) {
// Break, display some message or all together
}
}
}
public boolean methodA() {
return true;
}
public boolean methodB() {
return false;
}
}

How to unit test side effecting logic

I have a following code
public class Component extend Framework {
private Integer someInt;
private String someString;
public Integer getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
Integer tempInt = (Integer)getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = (Integer)getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = (Integer)getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
Basically activate() method is called by the framework in order to access internal state of the framework to construct Component object. activate() is sort of like a setter for the Component object.
If I were to unit test the code above, what would be the best way to do it without having to have framework running?
One way would be to mock out Component class and stub the super.getProperties... calls, however if we mock the class in question, what is the point of testing to begin with?
I will show how to test one edge case
void testServiceCallWithNoKeyPropertyFound() {
Component componentUnderTest = new Component() {
Integer getProperties(String key) {
return null; // property should not be found
}
Request getRequest() {
return new Request(...); //this request should not contain a property named "key",
}
Bind getBind() {
return new Bind(...); //this bind should not contain a property named "key"
}
String makeServiceCall(String url) {
if (url.endsWith("null")) {
return success;
}
throw new AssertionError("expected url ending with null, but was " + url);
}
};
componentUnderTest.activate();
assertThat(componentUnderTest.getSomeString(), equalTo("success"));
}
Using Mockito (spys) can make this example much more concise. But this would hide the principles how to design the test.
There are some more edge cases:
void testServiceCallWithPropertyFoundInComponent() ...
void testServiceCallWithPropertyFoundInRequest() ...
void testServiceCallWithPropertyFoundInBind() ...
Use Mockito.
Spy the Component class and mock the methods getRequest() and getBind().
Finally, call the activate() method directly from your unit test.
I think it could be a smell of bad design. Maybe you should consider composition instead of inheritance? It would be more testing friendly and more objective. Why Component is inheriting from Framework class?
public class Component {
private int someInt;
private String someString;
private Framework framework;
public Component(Framework framework) {
this.framework = framework
}
public int getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
int tempInt = framework.getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = framework.getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = framework.getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}

EasyMock: How to Verify Method Order for Set of Values Where Order of Set Does Not Matter

I have a test in which I have a set of specific values for which two different methods will execute once for each value in the set. I need to check that the two methods are called in a specific order in relation to each other, but not in relation to the order of the set of values. For example:
String[] values = { "A", "B", "C" };
for (...<loop over values...) {
methodOne(value);
methodTwo(value);
}
It does not matter which order values is in, but I need to verify that methodOne() and methodTwo() are called for each value in the set AND that methodOne() is always called before methodTwo().
I know that I can create a control and expect methodOne() and methodTwo() for each value, then do control.verify(), but this depends on values being in a specific order.
Is there an elegant way to do this?
Thanks
You can do this using andAnswer().
Basically, inside the andAnswer() from methodOne() you set some variable to hold what the passed in value was.
Then in the andAnswer() for methodTwo() you assert that the same argument matches what you saved from your methodOne answer.
Since each call to methodOne will modify this variable it will make sure methodTwo() is always called after methodOne().
Note this solution is not thread safe
First you need something to hold the variable from the methodOne call. This can be a simple class with a single field or even an array of one element. You need this wrapper object because you need to reference it in the IAnswer which requires a final or effectively final field.
private class CurrentValue{
private String methodOneArg;
}
Now your expectations. Here I called the class that you are testing (The System Under Test) sut:
String[] values = new String[]{"A", "B", "C"};
final CurrentValue currentValue = new CurrentValue();
sut.methodOne(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
//save the parameter passed in to our holder object
currentValue.methodOneArg =(String) EasyMock.getCurrentArguments()[0];
return null;
}
}).times(values.length); // do this once for every element in values
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
//check to make sure the parameter matches the
//the most recent call to methodOne()
assertEquals(currentValue.methodOneArg, value);
return null;
}
}).times(values.length); // do this once for every element in values
replay(sut);
... //do your test
verify(sut);
EDIT
you are correct that if you are using EasyMock 2.4 + you can use the new Capture class to get the argument value in a cleaner way for methodOne(). However, you may still need to use the andAnswer() for methodTwo() to make sure the correct values are called in order.
Here is the same code using Capture
Capture<String> captureArg = new Capture<>();
sut.methodOne(and(capture(captureArg), isA(String.class)));
expectLastCall().times(values.length);
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
assertEquals(captureArg.getValue(), value);
return null;
}
}).times(values.length);
replay(sut);
For those interested, I solved this issue using intended EasyMock functionality. The solution was to make a custom IArgumentMatcher to verify against a collection of values and to enforce how many times each value is matched consecutively. The custom matcher, in addition to using strict mocking exactly solves the original problem.
public class SetMatcher implements IArgumentMatcher {
private List<String> valuesToMatch;
private List<String> remainingValues;
private String currentValue = null;
private int timesMatched = 0;
private int setMatches;
public SetMatcher(final List<String> valuesToMatch, final int times) {
this.valuesToMatch = new ArrayList<String>(valuesToMatch);
this.remainingValues = new ArrayList<String>(valuesToMatch);
this.setMatches = times;
}
public String use() {
EasyMock.reportMatcher(this);
return null;
}
public void appendTo(StringBuffer buffer) {
if (this.remainingValues.size() == 0) {
buffer.append("all values in " + this.valuesToMatch + " already matched " + this.setMatches + " time(s)");
} else {
buffer.append("match " + this.valuesToMatch + " " + this.setMatches + " time(s) each");
}
}
public boolean matches(Object other) {
if (this.timesMatched >= this.setMatches) {
this.currentValue = null;
this.timesMatched = 0;
}
if (null == this.currentValue) {
if (this.remainingValues.contains(other)) {
this.currentValue = (String) other;
this.timesMatched = 1;
this.remainingValues.remove(other);
return true;
}
} else if (this.currentValue.equals(other)) {
this.timesMatched++;
return true;
}
return false;
}
}
The class being tested:
public class DataProcessor {
private ServiceOne serviceOne;
private ServiceTwo serviceTwo;
public DataProcessor(ServiceOne serviceOne, ServiceTwo serviceTwo) {
this.serviceOne = serviceOne;
this.serviceTwo = serviceTwo;
}
public void processAll(List<String> allValues) {
List<String> copy = new ArrayList<String>(allValues);
for (String value : copy) {
this.serviceOne.preProcessData(value);
this.serviceTwo.completeTransaction(value);
}
}
}
And the test:
public class DataProcessorTest {
List<String> TEST_VALUES = Arrays.asList("One", "Two", "Three", "Four", "Five");
#Test
public void test() {
IMocksControl control = EasyMock.createStrictControl();
ServiceOne serviceOne = control.createMock(ServiceOne.class);
ServiceTwo serviceTwo = control.createMock(ServiceTwo.class);
SetMatcher matcher = new SetMatcher(TEST_VALUES, 2);
for (int i = 0; i < TEST_VALUES.size(); i++) {
serviceOne.preProcessData(matcher.use());
serviceTwo.completeTransaction(matcher.use());
}
control.replay();
DataProcessor dataProcessor = new DataProcessor(serviceOne, serviceTwo);
dataProcessor.processAll(TEST_VALUES);
control.verify();
}
}
The test will fail for any of the following:
ServiceOne and ServiceTwo are called in the wrong order
ServiceOne and ServiceTwo are not called consecutively with the same value
ServiceOne or ServiceTwo are called with a value that is not in the specified value list
A call is made beyond the number of expected times for a value in the list

Check if a method was called inside another method

Is there any way in java to check if a certain method was called inside another method? I am testing a class and the method I am having trouble with plays sound and there is virtually no way of getting the audio file that is played(private attribute inside an inner class) without changing the code. However the way the method plays sounds is it calls a method that plays a single sound (playSadMusic, playHappyMusic, etc). Those methods are in an interface that I have to create a mock object for. I'm a little stuck on how I would exactly go about testing this. Any thoughts? Any other ideas on how I could possibly test this other than check if a certain method was call are welcome.
I am using JMock 2.6.0 and JUnit 4
the audio inteface
public interface StockTickerAudioInterface {
public abstract void playHappyMusic();
public abstract void playSadMusic();
public abstract void playErrorMusic();
}
anther interface I have to create a mock for
public interface StockQuoteGeneratorInterface {
public abstract StockQuoteInterface getCurrentQuote() throws Exception;
public abstract String getSymbol();
public abstract void setSymbol(String symbol);
public abstract StockQuoteGeneratorInterface createNewInstance(String symbol);
}
the class being tested
public class StockQuoteAnalyzer {
private StockTickerAudioInterface audioPlayer = null;
private String symbol;
private StockQuoteGeneratorInterface stockQuoteSource = null;
private StockQuoteInterface lastQuote = null;
private StockQuoteInterface currentQuote = null;
public StockQuoteAnalyzer(String symbol,
StockQuoteGeneratorInterface stockQuoteSource,
StockTickerAudioInterface audioPlayer)
throws InvalidStockSymbolException, NullPointerException,
StockTickerConnectionError {
super();
// Check the validity of the symbol.
if (StockTickerListing.getSingleton().isValidTickerSymbol(symbol) == true){
this.symbol = symbol;
} else {
throw new InvalidStockSymbolException("Symbol " + symbol
+ "not found.");
}
if (stockQuoteSource == null) {
throw new NullPointerException(
"The source for stock quotes can not be null");
}
this.stockQuoteSource = stockQuoteSource;
this.audioPlayer = audioPlayer;
}
public double getChangeSinceLast() {
double retVal = 0.0;
if (this.lastQuote != null) {
double delta = this.currentQuote.getLastTrade() - this.lastQuote.getLastTrade();
retVal = 100 * (delta / this.lastQuote.getLastTrade());
}
return retVal;
}
public double getChangeSinceYesterday() {
double delta = (this.currentQuote.getLastTrade() - this.currentQuote
.getClose());
return 100 * (delta / this.currentQuote.getClose());
}
public void playAppropriateAudio() {
if ((this.getChangeSinceYesterday() > 2)
|| (this.getChangeSinceLast() > 0.5)) {
audioPlayer.playHappyMusic();
}
if ((this.getChangeSinceYesterday() < -2)
|| (this.getChangeSinceLast() < -0.5)) {
audioPlayer.playSadMusic();
}
}
}
If you use Mockito you can use verify() to check the number of times a method was called. Use it like this:
verify(mockedObject, times(1)).methodToValidate();
You can check if methodToValidate() was called with a specific string, e.i verify(mockedObject, times(1)).methodToValidate("a specific value"); or you can use it with anyString() like this: verify(mockedObject, times(1)).methodToValidate(anyString());.
Unless this method is called with your specified paramterer, the test will fail
Read more about verify here.
UPDATE
Since your edited post states that you are using jMock, a quick googeling showed me that it is possible to achieve a similar behaviour with jMock and it's expect method. It's used as below:
mockedObject.expects(once()).method("nameOfMethod").with( eq("An optional paramter") );
More detailed explanation can be found by reading jMocks getting started page.
say you have a method child() which is called in parent()
public void parent() {
child();
}
In child() to get the last method it got invoked from, you can use StackTraceElement
public void child() {
StackTraceElement[] traces = Thread.currentThread().getStackTrace();
boolean check = false;
for(StackTraceElement element : traces) {
if(check) {
System.out.println("Calling method - " + element.getMethodName());
}
if(element.getMethodName().equals("child")) {
check = true;
}
}
}
If you are writing a mock object with the methods you want to check whether they were called, you can implement the methods in a way they raise some flag when they are called, for example
public void playHappyMusic() {
this.wasCalled = true;
}
wasCalled being a public (or with getters) class variable. Then you just check the flag.
Provide you are in the same thread as the calling method, you can check the stack trace in any given moment this way:
Thread.currentThread().getStackTrace()
You can see what method are called doing it like this:
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste);
}
For example:
public class Test {
public static void main (String[]s){
Test test = new Test();
test.makeTest();
}
public void makeTest(){
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
System.out.println(ste);
}
}
results in
java.lang.Thread.getStackTrace(Unknown Source)
Test.makeTest(Test.java:17)
Test.main(Test.java:11)

Categories

Resources