Testing console output - java

Got a question regarding testing the console output.
stdOutput class:
public abstract class StdOutTest {
private final PrintStream stdOutMock = mock(PrintStream.class);
private final PrintStream stdOutOrig = System.out;
#Before
public void setUp() {
System.setOut(this.stdOutMock);
}
#After
public void tearDown() {
System.setOut(this.stdOutOrig);
}
protected final PrintStream getStdOutMock() {
return this.stdOutMock;
}
}
Now here is something I don't understand:
public class test extends StdOutTest{
#Before
public void setUp(){
//empty
}
#Test
public void example(){
System.out.println("hello");
verify(getStdOutMock()).println("hello");
}
}
I use Mockito for the verify and this test passes when I delete setUp(), but with the setUp() it fails. the fail message says:
hello
Wanted but not invoked:
printStream.println("hello");
-> at observer_test.test.example(test.java:18)
Actually, there were zero interactions with this mock.
Can anyone help me perhaps on why this happens?

Your subclass is overriding the setUp method of the superclass with an empty method. You can fix this by adding a call to the superclass method:
#Before
public void setUp(){
super.setUp();
}
Or you can just delete the setUp method in the subclass it if you don't need to perform any custom setup in there.

Related

How can I use the #BeforeEach method for testing in Java?

I am learning Test Driven Development with JUnit5. In my reader this is written: " Annotations are added above a method to specify its behavior. A common scenario we find ourselves in is that
we have to create a new object for each test. Instead of doing this in each test method, we can create a new method called setUp() for example, and add the #beforeEach annotation. This will make sure that this method is executed before each test method." But I don't know how can I use an object from a method in another method. Any help, please? This is my code:
#BeforeEach
public void setUp(){
IntSet set = new IntSet(4);
}
#Test
public void testIntSet(){
assertEquals(set.getCapacity(), 4); //error here: Cannot resolve symbol 'set'
}
You have all your tests in a class, right? Make it a property/instance variable:
class SomeTests {
IntSet set;
#BeforeEach
public void setUp() {
set = new IntSet(4);
}
#Test
public void testIntSet() {
assertEquals(set.getCapacity(), 4);
}
}
You have to declare IntSet set as a field in your test class. Then, you can initialize the field in the #BeforeEach method.
class MyTest{
private IntSet set;
#BeforeEach
public void setUp(){
set = new IntSet(4);
}
#Test
public void testIntSet(){
assertEquals(set.getCapacity(), 4); //error here: Cannot resolve symbol 'set'
}
}
You need to declare your variable outside of the setUp() method. This way it is accessible for any method.
private IntSet set;
#BeforeEach
public void setUp(){
set = new IntSet(4);
}
#Test
public void testIntSet(){
assertEquals(set.getCapacity(), 4); //error here: Cannot resolve symbol 'set'
}

JUnit #Parameterized function is run before #BeforeClass in a test suite?

I am using a JUnit test suite to run a few tests, one of which is run multiple times using #Parameterized. I am finding that when I run my tests, the #Parameterized function is run before #BeforeClass. Is this expected behavior or is something else happening? I would have expected that #BeforeClass would run before any of the tests are started.
Here is my test suite:
#RunWith(Suite.class)
#SuiteClasses({ Test1.class, Test2.class })
public class TestSuite {
#BeforeClass
public static void setup() throws Exception {
// setup, I want this to be run before anything else
}
}
Test1 uses #Parameterized:
public class Test1 {
private String value;
// #Parameterized function which appears to run before #BeforeClass setup()
#Parameterized.Parameters
public static Collection<Object[]> configurations() throws InterruptedException {
// Code which relies on setup() to be run first
}
public Test1(String value) {
this.value = value;
}
#Test
public void testA() {
// Test
}
}
How can I fix this to run the #BeforeClass setup() function before running anything else?
This is, unfortunately, working as intended. JUnit needs to enumerate all of the test cases before starting the test, and for parameterized tests, the method annotated with #Parameterized.Parameters is used to determine how many tests there are.
Although beeing a bit different solution, a static block does the trick. Also note, that it must be in the Test1.class. But beside of that it works ;-)
#RunWith(Parameterized.class)
public class Test1 {
static{
System.out.println("Executed before everything");
}
private String value;
// #Parameterized function which appears to run before #BeforeClass setup()
#Parameterized.Parameters
public static Collection<Object[]> configurations() throws InterruptedException {
// Code which relies on setup() to be run first
}
public Test1(String value) {
this.value = value;
}
#Test
public void testA() {
// Test
}
}
Recently ran into similar issue and solved problem using Function. Example below.
#RunWith(Parameterized.class)
public class MyClassTest {
#Parameterized.Parameters
public static Iterable functions() {
return Arrays.<Object, Object>asList(
param -> new Object()
);
}
Object param;
Function function;
public MyClassTest(Function f) {
this.function = f;
}
#Before
public void before() {
// construct dependency
param = "some value";
}
#Test
public void test() {
assertThat(myClass.doSomething(function.apply(param)), is(equalTo(expectedValue)));
}
}
In your scenario, do database setup in #Before or #BeforeClass then inject into function
I found a hack to force a code segment to run before all other methods that are annotated with #Parameterized.Parameters.
Just create a parameterized dummy test as follows:
#RunWith(Parameterized.class)
public class DummyInitTest
{
#Parameterized.Parameters
public static Collection<?> constructorFeeder()
{
// Your setup here. This will run before anything else.
// Return empty list so no tests will be executed for this test class.
return ImmutableList.of();
}
}
Then in your test suite, add this test first:
#RunWith(Suite.class)
#SuiteClasses({ DummyInitTest.class, Test1.class, Test2.class })
public class TestSuite {
// ...
}
Hoping this can help someone, I simply did it this way:
//#BeforeClass does not run before Parameters annotation
public static void beforeClassSetup() throws IOException {
InputStream is = Test.class.getResourceAsStream("/TestData.json");
// load data...
}
#Parameters(name = "testProductFunctionality")
public static Collection<Object[]> data() throws IOException {
beforeClassSetup();
// create parameters...
}
#Test
public void testProductFunctionality() {
//...

How to call real methods in class instances annotated with #Injectable in JMockit?

I'm looking for a way in JMockit to inject the private fields inside a class while maintaining the ability to trigger the real methods. I use #Injectable and #Tested offered by JMockit. But somehow after that the injected instance is not able to call the real method.
Example test:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
doSomething.execute();
}
}
Here DoSomething wraps the Call instance, which provides a way to print a message. The ideal output of the four test cases would be:
real
real
real
fake
However the actual scenario is that only 3 and 4 worked, printing:
real
fake
This shows if an instance is created using #Injectable. It's not able to directly call the original method without copying and pasting the old method body to the mocked version. That seems really awkward. Is there a workaround of this?
My understanding is that if you use #Injectable you just get an empty mock and then you can no longer call the original method.
The workaround that I would use is to do the injection "manually" like this:
public class TestClass {
public static class DoSomething {
private Call callee;
public void execute() {
callee.call();
}
}
public static class Call {
public void call() {
System.out.println("real");
}
}
#Tested DoSomething doSomething;
//#Injectable Call call;
// nothing happens
#Test
public void testRealCall() {
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// invocation doesn't help either
#Test
public void testRealCallSecondTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call(Invocation inv) {
inv.proceed();
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
// this works, but requires redundant methods
#Test
public void testRealCallThirdTry() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("real");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
#Test
public void testFakeCall() {
new MockUp<Call>() {
#Mock
#SuppressWarnings("unused")
public void call() {
System.out.println("fake");
}
};
Deencapsulation.setField(doSomething, "callee", new Call());
doSomething.execute();
}
}
I ran into this question when I had the same problem. However, the existing answer don't work with newer versions of JMockit.
If a field in the tested class is annotated with #Inject, a corresponding #Injectable is required in the test class. Usually. This means that removing the #Injectable and instead mock the class with MockUp suggested in the other answer doesn't work. JMockit will complain with "Missing #Injectable for field ...".
What needs to be done instead is to change the #Injectable annotation to a #Tested annotation, i.e. change this
#Injectable Call call;
to
#Tested Call call;
call becomes a real instance and JMockit doesn't complain about a missing #Injectable. If you need to mock some methods in call, it can be done with MockUp as usual.
new MockUp<Call>() {
#Mock
public void someMethodToMock() {
}
};

JUnit test on setters and getters failing

i'm getting a nullpointerexception when i run the junit test in eclipse. what am i missing here?
MainTest
public class MainTest {
private Main main;
#Test
public void testMain() {
final Main main = new Main();
main.setStudent("James");
}
#Test
public void testGetStudent() {
assertEquals("Test getStudent ", "student", main.getStudent());
}
#Test
public void testSetStudent() {
main.setStudent("newStudent");
assertEquals("Test setStudent", "newStudent", main.getStudent());
}
}
setters and getters are in the Main class
Main
public String getStudent() {
return student;
}
public void setStudent(final String studentIn) {
this.student = studentIn;
}
thanks.
You need to initialize your main object before using it
You can do it either on an #Before method or inside the test itself.
OPTION 1
Change
#Test
public void testSetStudent() {
main.setStudent("newStudent");
assertEquals("Test setStudent", "newStudent", main.getStudent());
}
to
#Test
public void testSetStudent() {
main = new Main();
main.setStudent("newStudent");
assertEquals("Test setStudent", "newStudent", main.getStudent());
}
OPTION 2
Create a #Before method, when using #Before the main field will be created before any #Test is executed, there is another option, option 3, to use #BeforeClass
#Before
public void before(){
main = new Main();
}
OPTION 3
#BeforeClass
public static void beforeClass(){
//Here is not useful to create the main field, here is the moment to initialize
//another kind of resources.
}
Every test method gets a new instance of MainTest. This means that the changes you make in your first method won't show up in your second method, and so on. There is no sequential relationship between one test method and another.
You need to make each method a self-contained test that tests one aspect of your class's behaviour.

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