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);
Related
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);
}
Is there some way to disable creation new instance of Test per #Test ?
One instance per test is the way JUnit works by default. You can, however, write your own test runner which uses one single instance for all tests. You'll probably want to start by extending BlockJUnit4ClassRunner.
For the sake of making this an answer:
public class MyTestClass {
private static String onceForAllTests;
#AfterClass
public static void afterClass() {
onceForAllTests = null; // silly, but just to demonstrate
}
#BeforeClass
public static void beforeClass() {
onceForAllTests = "This is set once for all tests";
}
#Test
public void sillyTest {
String someTestValue = "This is set during method";
assertNotEquals( onceForAllTests, someTestValue );
}
}
I ended up arriving independently at the solution suggested above by Mathew. I thought would post my short solution here.
The code in Kotlin:
class SingleInstanceRunner<T>(clazz : Class<T>) : BlockJUnit4ClassRunner(clazz) {
val instance : Any by lazy { super.createTest() }
override fun createTest() = instance
}
Here is the (untested) Java translation of the above:
public class SingleInstanceRunner extends BlockJUnit4ClassRunner {
private Object instance;
public SingleInstanceRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}
#Override
protected synchronized Object createTest() throws Exception {
if (instance == null) {
instance = super.createTest();
}
return instance;
}
}
With this solution, annotate your test class with this runner.
In Kotlin:
#RunWith(SingleInstanceRunner::class)
class MyTest {
...
}
In Java:
#RunWith(SingleInstanceRunner.class)
public class MyTest {
...
}
This is used in combination with #FixMethodOrder to employ junit in some system test type scenarios.
I have a class with static methods that I'm currently mocking with JMockit. Say it looks something like:
public class Foo {
public static FooValue getValue(Object something) {
...
}
public static enum FooValue { X, Y, Z, ...; }
}
I have another class (let's call it MyClass) that calls Foo's static method; I'm trying to write test cases for this class. My JUnit test, using JMockit, looks something like this:
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
new Expectations() {
{
Foo.getValue((Object) any); result = Foo.FooValue.X;
}
};
}
myClass.doSomething();
}
This works fine and dandy, and when the test is executed my instance of MyClass will correctly get the enum value of Foo.FooValue.X when it calls Foo.getValue().
Now, I'm trying to iterate over all the values in the enumeration, and repeatedly run the test. If I put the above test code in a for loop and try to set the result of the mocked static method to each enumeration value, that doesn't work. The mocked version of Foo.getValue() always returns Foo.FooValue.X, and never any of the other values as I iterate through the enumeration.
How do I go about mocking the static method multiple times within the single JUnit test? I want to do something like this (but obviously it doesn't work):
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
for (final Foo.FooValue val : Foo.FooValue.values() {
new Expectations() {
{
// Here, I'm attempting to redefine the mocked method during each iteration
// of the loop. Apparently, that doesn't work.
Foo.getValue((Object) any); result = val;
}
};
myClass.doSomething();
}
}
}
Any ideas?
Instead of "mocking the method multiple times", you should record multiple consecutive return values in a single recording:
public class MyClassTest extends TestCase
{
#Test
public void testMyClass(#Mocked Foo anyFoo)
{
new Expectations() {{
Foo.getValue(any);
result = Foo.FooValue.values();
}};
for (Foo.FooValue val : Foo.FooValue.values() {
myClass.doSomething();
}
}
}
It could also be done with a Delegate, if more flexibility was required.
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).
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.