Non-void test methods in JUnit 4 - java

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).

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);

EasyMock #Mock is not working same as createMock for abstract classes

As per the answer here, #Mock annotation and createMock are same from functionality view. But, I am facing a strange issue while using these. Little background here.
I have to test ClassUnderTest which calls method from Abstractclass. When I should call from the unit test to ClassUnderTest, I expect the Abstractclass method to be called.
`
public abstract AbstractClass {
public void addValue(int a, int b) {
// Invoking another method which is abstract.
};
}
public class ClassUnderTest {
public Abstractclass obj;
public ClassUnderTest(Abstractclass obj) {
// Parameterized constructor.
}
public MethodToTest(){
object.addValue(1, 2); // Calls the method.
}
}
#RunWith(EasyMockRunner.class)
public class TestFile {
#Mock
private AbstractClass concrete;
#Test
public void testMethod() {
concrete = EasyMock.createMock(AbstractClass.class);
concrete.addValue(1,2);
EasyMock.expectLastCall().once();
EasyMock.replay();
new ClassUnderTest().methodToTest();
EasyMock.verify() // The code under scan.
}
}
`
I am facing these issues:
When I am using #Mock annotation, EasyMock verify throws an error saying Abstractclass.addValue() expectation is not fulfilled.
But, when I remove #Mock annotation, it works fine and no error is there.
For Non abstract classes, #Mock is working fine for me.
Could anybody please explain this behavior?
Your real code must be different from this one. Both should behave exactly the same. Otherwise it is a bug. I tried your code (applying a lot of fixes. You should post correctly running examples next time). It works perfectly. Here is it
abstract class AbstractClass {
public abstract void foo();
public void addValue(int a, int b) {
foo();
}
}
class ClassUnderTest {
private AbstractClass obj;
public ClassUnderTest(AbstractClass obj) {
this.obj = obj;
}
public void methodToTest(){
obj.addValue(1, 2); // Calls the method.
}
}
#RunWith(EasyMockRunner.class)
public class TestFile {
#Mock
private AbstractClass concrete;
#Test
public void testMethod() {
// concrete = EasyMock.createMock(AbstractClass.class);
concrete.addValue(1,2);
EasyMock.replay();
new ClassUnderTest(concrete).methodToTest();
EasyMock.verify(); // The code under scan.
}
}
To be super clear. These 4 mean exactly the same thing:
// 1. Calling once the void method
concrete.addValue(1,2);
// 2. Calling once the void method and then using expectLastCall()
concrete.addValue(1,2);
expectLastCall();
// 3. Calling once the void method and then expect once
concrete.addValue(1,2);
expectLastCall().once();
// 4. Calling once the void method and then expect one time
concrete.addValue(1,2);
expectLastCall().time(1);

Unit test with wrapped public static method Java

I am not very familiar with Unit Tests, I know that they are very important for code quality, and I want to write some in my project. I recently run into some issues. The context is that, I am writing the testClassA for my Aclass, but some functions in Aclass depend on BClass.
BClass is a utility function, so it has many public static function.
AClass uses Bclass's functions :
public class Aclass{
public boolean Afunction()
{
String result = Bclass.Bfunction();
//do stuff with result
return true
}
}
public class Bclass{
public static String Bfunction()
{
//function code
}
}
I want that everytime the BClass.Bfunction is called, then I can return what I want without really execute the real Bfunction in Bclass, so my Aclass doesn't depend on other class in my test. Is it possible ?
One approach that limits your changes to just the Aclass, and eliminates the dependency on Bclass (as you asked for) is extract-and-override:
Identify the code you wish to bypass in your test and extract it to a method.
Override that method in a sub-class of your class-under test. In this overidden method, you can code whatever mock behavior is appropriate for the test:
So your modified Aclass would look like this:
public class Aclass {
public boolean Afunction() {
String result = doBfunction();
// do stuff with result
return true;
}
// This is your "extracted" method.
protected doBfunction() {
return Bclass.Bfunction();
}
}
and your test class would look like this:
class AClassTest {
#Test
public void testAFunction() {
Aclass testObject = new TestableAclass();
boolean value = testObject.AFunction();
// now you can assert on the return value
}
class TestableAclass extends Aclass {
#Override
protected String doBfunction() {
// Here you can do whatever you want to simulate this method
return "some string";
}
}
}

Junit 4, how to disable creating new instance of Test per test method

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.

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