Test update method of Observer with EasyMock - java

I am trying to test if the update method in a class which implements the Observer interface is called. I am using EasyMock to mock the ConcreteObserver so that I can verify that his update function is really executed.
This is my subject, the Observable class:
public class Subject extends java.util.Observable {
public funcA() {
...
notifyObservers(this,aVariable);
...
}
}
I have the following class which is the Observer:
public class ConcreteObserver implements java.util.Observer {
public ConcreteObserver(Subject subject) {
subject.observer(this);
}
#Override
public void update(Observable o, Object arg) {
// TODO
}
}
And this is my unit test:
#Test
public void testUpdateFunction() {
Subject subj = new Subject();
ConcreteObserver mockedObserver = EasyMock.
createMockBuilder(ConcreteObserver.class).
withConstructor(subj).
addMockedMethod("update").
createMock();
mockedObserver.update((Observable) EasyMock.anyObject(),EasyMock.anyObject());
EasyMock.replay(mockedObserver);
subj.funcA();
EasyMock.verify(mockedObserver);
}
Unfortunately I receive the following error :
Expectation failure on verify: ConcreteObserver.update(, ): expected: 1, actual: 0
Any ideas on how to solve this issue ?

If you want to test ConcreteObserver test it in isolation to your Subject; if you want to test Subject do it like this (which assumes an import static of EasyMock):
#Test
public void testUpdateFunction()
{
Subject subject = new Subject();
Observer observer = createMock(Observer.class);
observer.update(eq(subject), anyObject());
replay(observer);
subject.observer(observer);
subject.funcA();
verify(observer);
}

Related

Mock a callback function using Mockito

I am writing unit test cases in java using Junit. I have a function with call back function.
public class RedisCacheServiceImpl implements CacheService {
public <T> T useCacheElseCompute(String key, Class<T> valueClass, Supplier<T> compute, Long expiryInSeconds) {
// .....Body............
}
}
In another class
public class NotificationTemplateServiceImpl implements NotificationTemplateService {
public NotificationTemplateDTO getNotificationMessage(NotificationDTO notificationDTO) {
// .....data....
NotificationTemplateDTO notificationTemplateDTO = cacheService.useCacheElseCompute(
templateCacheKey, NotificationTemplateDTO.class,
() -> notificationTemplateRepository.getNotificationTemplate(notificationType, deliveryType),
cacheExpiryInSeconds
);
}
//.......logic...
I am writing unit test cases for getNotificationMessage function but getting Incompatible equality constraint issue.
Unit Test:-
#Test
void testGetNotificationMessage() {
Mockito.when(mockCacheService.useCacheElseCompute(
templateCacheKey,
NotificationTemplateDTO.class,
ArgumentMatchers.<Supplier<NotificationTemplateRepository>>any()),
any(Long.class)
).thenReturn(null);
}
when(mockCacheService.useCacheElseCompute(eq(templateCacheKey),
eq(NotificationTemplateDTO.class),any(Supplier.class), eq(86400L))).thenReturn(null);

In testing in java how to check if a method of an interface is called or not?

I want to test this class which calls a method of interface using anonymous class.
public class ClassToTest
{
public void methodToTest()
{
InterefaceToMock interefaceToMockReference = new InterefaceToMock() {
#Override
public int methodToMock()
{
return 0;
}
};
interefaceToMockReference.methodToMock();
}
}
This is the interface
public interface InterefaceToMock
{
public int methodToMock();
}
I am using this approch to check it methodToMock is called or not
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.FullVerificationsInOrder;
import mockit.Mocked;
import mockit.NonStrictExpectations;
public class TestAClass
{
#Mocked InterefaceToMock interefaceToMockReferenceMocked;
#Test
public void test1()
{
new NonStrictExpectations()
{
{
interefaceToMockReferenceMocked.methodToMock();times=1;
}
};
(new ClassToTest()).methodToTest();
new FullVerificationsInOrder(interefaceToMockReferenceMocked)
{
};
assertTrue(true);
}
}
But test case fails.
Can anyone help.
Your original test was almost correct. It declared the mock field as simply being #Mocked, which merely gives you a single mocked instance implementing the interface, and this is not the one used by the code under test. The JMockit API has another mocking annotation, however, which extends mocking to all implementation classes from a given base type, and by default affects all instances of said classes. So, the test should be changed as follows:
public class TestAClass
{
#Capturing InterfaceToMock anyImplementingInstance;
#Test
public void test1()
{
new ClassToTest().methodToTest();
new Verifications() {{
anyImplementingInstance.methodToMock();
}};
}
}
In the general case, if you have an class and you want to check whether a method on a Mock of that class is called, you use Mockito.verify.
For example:
public class AppTest {
#Test
public void testMe() {
final ITest iTest = Mockito.mock(ITest.class);
final CUT cut = new CUT(iTest);
cut.doStuff();
Mockito.verify(iTest).someStuff();
}
interface ITest {
void someStuff();
}
class CUT {
private final ITest iTest;
CUT(ITest iTest) {
this.iTest = iTest;
}
public void doStuff() {
iTest.someStuff();
}
}
}
Here, the test is whether ITest.someStuff() is called from CUT.doStuff().
Your example is undecipherable...

TestNG retryAnalyzer only works when defined in methods #Test, does not work in class' #Test

This works as supposed, test fails (due to haltTesting()) and is repeated 2x
public class A0001_A0003Test extends TestControl {
private Kunde kunde = Kunde.FR_WEHLITZ;
#Test(retryAnalyzer = TestRepeat.class, groups = {TestGroups.FAILED}, description = "verify adress")
public void testkundenDaten_Angaben() throws Exception {
bifiTestInitial();
testActions.selectKunde(kunde);
haltTesting();
}
}
but because i have multiple tests in one class, i defined the repeatAnalyzer on class level
#Test(retryAnalyzer = TestRepeat.class)
public class A0001_A0003Test extends TestControl {
private Kunde kunde = Kunde.FR_WEHLITZ;
#Test(groups = {TestGroups.FAILED}, description = "verify adress")
public void testkundenDaten_Angaben() throws Exception {
bifiTestInitial();
testActions.selectKunde(kunde);
haltTesting();
}
}
but then the test is not repeated, the documentation says:
The effect of a class level #Test annotation is to make all the
public methods of this class to become test methods even if they are
not annotated. You can still repeat the #Test annotation on a method
if you want to add certain attributes.
So it should have been possible or am I expecting the wrong outcome?
My solution was to set a retryAnalyzer for all methods in the #BeforeSuite method.
But do not set it in beforeMethod because then it will be re-created each invocation with a new counter => endless loop.
#BeforeSuite(alwaysRun = true)
public void beforeSuite(ITestContext context) {
TestRepeat testRepeat = new TestRepeat();
for (ITestNGMethod method : context.getAllTestMethods()) {
method.setRetryAnalyzer(testRepeat);
}
}
You can implement IAnnotationTransformer listener and register listener cmd line or in config file or at class level.
public class MyAnnotationTransformer implements
IAnnotationTransformer {
#Override
public void transform(ITestAnnotation testAnnotation, Class clazz, Constructor testConstructor,
Method method) {
testAnnotation.setRetryAnalyzer(TestRepeat.class);
}
...
}
To register at class level:
#Listeners(value=MyAnnotationTransformer.class)
public class A0001_A0003Test extends TestControl {
...
}

Non-void test methods in JUnit 4

I would like a JUnit 4 test class to implement the same interface as the class its testing. This way, as the interface changes (and it will, we're in early development), the compiler guarantees that corresponding methods are added to the test class. For example:
public interface Service {
public String getFoo();
public String getBar();
}
public class ServiceImpl implements Service {
#Override public String getFoo() { return "FOO"; }
#Override public String getBar() { return "BAR"; }
}
public class ServiceTest implements Service {
#Override
#Test
public String getFoo() {
//test stuff
}
#Override
#Test
public String getBar() {
//test stuff
}
}
When I try this, I get an error: "java.lang.Exception: Method getFoo() should be void",
presumably because test methods must return void. Anybody know of any way around this?
I have to admit, it is a neat trick, though it doesn't scale well to multiple test scenarios.
Anyways, you can use custom runner. For example:
#RunWith(CustomRunner.class)
public class AppTest {
#Test
public int testApp() {
return 0;
}
}
public class CustomRunner extends JUnit4ClassRunner {
public CustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
protected void validate() throws InitializationError {
// ignore
}
}
A more natural way would probably be to use a code coverage tool, such as Cobertura. It integrates with JUnit nicely AND it shows you cases where your tests may be deficient in some cases (there are many cases such a tool won't catch though).

java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")

I'm using EasyMock(version 2.4) and TestNG for writing UnitTest.
I have a following scenario and I cannot change the way class hierarchy is defined.
I'm testing ClassB which is extending ClassA.
ClassB look like this
public class ClassB extends ClassA {
public ClassB()
{
super("title");
}
#Override
public String getDisplayName()
{
return ClientMessages.getMessages("ClassB.title");
}
}
ClassA code
public abstract class ClassA {
private String title;
public ClassA(String title)
{
this.title = ClientMessages.getMessages(title);
}
public String getDisplayName()
{
return this.title;
}
}
ClientMessages class code
public class ClientMessages {
private static MessageResourse messageResourse;
public ClientMessages(MessageResourse messageResourse)
{
this.messageResourse = messageResourse;
}
public static String getMessages(String code)
{
return messageResourse.getMessage(code);
}
}
MessageResourse Class code
public class MessageResourse {
public String getMessage(String code)
{
return code;
}
}
Testing ClassB
import static org.easymock.classextension.EasyMock.createMock;
import org.easymock.classextension.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ClassBTest
{
private MessageResourse mockMessageResourse = createMock(MessageResourse.class);
private ClassB classToTest;
private ClientMessages clientMessages;
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.replay(mockMessageResourse);
}
}
When I'm running this this test I'm getting following exception:
java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")
While debugging what I found is, it's not considering the mock method call
mockMessageResourse.getMessage("ClassB.title") as it has been called from the construtor (ClassB object creation).
Can any one please help me how to test in this case.
Thanks.
You need to call EasyMock.replay(mock) before calling the method under test. After calling the method under test you can call EasyMock.verify(mock) to verify the mock is called.
Next you need to add another expect call with the "title" argument since you call it twice.
Code:
EasyMock.expect(mockMessageResourse.getMessage("title")).andReturn("title");
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.verify(mockMessageResourse);
In my case, it was caused by the omission of a return value specification (andReturn(...)).
http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html for more details.
This can have various causes (someMock is the name of your mocked Object in this answer).
On the one side it can be that you need to expect the call via
expect(someMock.someMethod(anyObject()).andReturn("some-object");
like in Reda's answer.
It can also be that you forgot to call replay(someMock) before you used the mock, like you can see in Julien Rentrop's answer.
A last thing that is possible that wasn't mentioned here is that you used the mock somewhere else before in a test and forgot to reset the mock via reset(someMock).
This can happen if you have multiple Unit Tests like this:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
This will fail on one test with the IllegalStateException, because the mock a was not reset before being used in the next test. To solve it you can do the following:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#After
public void tearDown() throws Exception {
reset(a); // reset the mock after each test
}
You should put your call to replay after the expect calls, and before you use your mock. In this case you should change your test to something like this:
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
}
For me, this exception was occurring because the method I was trying to stub was final (something I hadn't realized).
If you want to stub a final method you'll need to use Powermock.

Categories