Very very simple class:
public class ConsoleHandler {
public void write(String message) {
System.out.println(message);
}
}
How do I test that when I call write("hello"), System.out.println("hello") is called? And also, is this unit test even worth it?
As for whether it is worth testing, it depends on why your are outputting. I usually do test System.out calls when writing command line utilities because that is the user interface and the text output matters. It's not even hard to do - just regular Java code.
The below technique shows how you can capture the values of System.out. You don't even need a mock framework. Note that it stores the "real" System.out so it can put it back at the end. If you don't do this, your other tests/code can quickly become confusing.
import static org.junit.Assert.*;
import java.io.*;
import org.junit.*;
public class ConsoleHandlerTest {
private PrintStream originalSysOut;
private ByteArrayOutputStream mockOut;
#Before
public void setSysOut() {
originalSysOut = System.out;
mockOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(mockOut));
}
#After
public void restoreSysOut() {
System.setOut(originalSysOut);
}
#Test
public void outputIsCorrect() {
new ConsoleHandler().write("hello");
assertEquals("message output", "hello".trim(), mockOut.toString().trim());
}
}
No, this unit test is not worth the time or the disk space. Unit testing is to make sure you get logic right. If there's no logic, there is nothing to be gained from the test. Its cost-benefit ratio is infinite.
You should unit test a method if it has branching logic, loops, or exception handling. But if all it does is call another method, then forget it. The best way to find out whether method X calls method Y is to look at the code.
Having said that, if you do insist on testing this, you should use the System.setOut method, passing a ByteArrayOutputStream that you've wrapped in a PrintStream, and then verify the contents of the underlying byte[] at the end.
You can use libraries such as Mockito ( http://code.google.com/p/mockito/ ) to mock classes as well as interfaces.
That said, you shouldn't be using Sysout in the first place. Use a logger such as Log4J or a logging facade such as SLF4J ( http://www.slf4j.org/ ). SLF4J has a testing framework that will make testing easier ( http://projects.lidalia.org.uk/slf4j-test/ )
And of course, JUnit or TestNG to set your test cases up.
To your first question "How do I test that when I call write("hello"), System.out.println("hellow") is called?"
You can use Mockito and follow the instructions in this answer: Mockito : how to verify method was called on an object created within a method?
To your second question "is this unit test even worth it?" As the test is, no, it doesn't make sense. However you can use this as a template, checking in the future if any method was called.
Related
This seems highly unlikely, but is there a way I could mock a static method in a certain way and the second time in another way?
A case scenario -
if(StringUtils.isEmpty("")) {
throw Exception();
}
...
if(StringUtils.isEmpty("")) {
doSomething();
}
The test is written in following way.
mockStatic(StringUtils.class);
when(StringUtils.isEmpty("")).thenReturn(false);
/*Is it possible to make this behaviour run only once such that second time
when it is called we can mock it again.*/
limitStaticMock(times(1));//Is this possible?
when(StringUtils.isEmpty("")).thenReturn(true);//Setting behaviour again.
You shouldn't use mocking to control such "internals".
You can easily control what your code under test is doing by controlling the string value that gets to that static call. You want the test to give true; then write a test that pushes in an empty string; and that expects an exception.
You have another production code method that shouldn't throw - then write up another test; and do the necessary setup.
But do not start mocking such methods. If you think you have to, then your design is not testable; in other words: broken! Fix your design, instead of using the big mocking hammer!
This question already has answers here:
Using JUnit to test a main method that requires simulation of keyboard input with an input stream?
(2 answers)
JUnit test for System.out.println()
(14 answers)
Closed 6 years ago.
I wrote a class which takes input from console and arguments in main method. The main method calls different methods for different console inputs and it calls different function for different arguments. So i want to test this main method with Junit by mimicking these inputs from a file. how can i do it? Is there any special provision in junit to test the main method of the class?
To provide the input from a file, make a FileInputStream and set that as the System.in stream. You'll probably want to set the original back after the main method has finished to make sure anything using it later still works (other tests, JUnit itself...)
Here's an example:
#Test
public void testMain() throws IOException {
System.out.println("main");
String[] args = null;
final InputStream original = System.in;
final FileInputStream fips = new FileInputStream(new File("[path_to_file]"));
System.setIn(fips);
Main.main(args);
System.setIn(original);
}
In your actual code you'll want to handle any IOExceptions and use something better than a full path to the file (get it via the classloader), but this gives you the general idea.
EDIT:
A couple years and some more wisdom later, I'd have to agree with Michael Lloyd Lee mlk's answer as the better approach and what should be preferred if possible. In the class containing your main method (or even a separate class) there ought to be a method that accepts an arbitrary InputStream and the arguments array. It could be a static method. The main method then simply calls it with the System.in stream as argument.
public class Main {
public static void main(String[] args) {
start(System.in, args);
}
public static void start(InputStream input, String[] args) {
// use input and args
}
}
Or alternatively you could have a class with a constructor accepting the arguments array to create a properly configured instance and then call an instance method on it that accepts an InputStream, like so:
public class Main {
public static void main(String[] args) {
Bootstrapper bootstrapper = new Bootstrapper(args);
bootstrapper.start(System.in);
}
}
public class Bootstrapper { // just some name, could be anything else
// could have some instance fields here...
public Bootstrapper(String[] args) {
// use the args to configure this instance, set fields, get resources...
}
public void start(InputStream input) {
// use input
}
}
Whatever fits the requirements and program design best. In both cases you end up with something that can be unit-tested with an InputStream obtained from a file. A test doing a simple static method call to Main.start, or a test creating a Bootstrapper instance and then calling its start method. Now your testing is no longer dependent on the System.in stream. The main method does minimal work and is simple enough for you to just trust its correctness without a separate test. At some point a piece of code becomes so trivial that testing it is equivalent to distrusting the compiler. And an issue in these main methods would become apparent very soon as it's the one method you know will always be called. A main method that does too much or is complex usually points to a lack of modularization in the code.
I leave the original answer in because it does offer a solution in case you really can't get past the use of System.in and testing the main method. That's why I wrote it in the first place, because I couldn't be certain about the asker's constraints. Sometimes someone just wants a straight answer to their exact question because the better approach is not available; you're not allowed to change the code, or refactoring it is too much effort and there's no budget, or some library is used that is hardcoded to use the system streams etc. Note that the original answer is less robust anyway. If the tests are run in parallel instead of sequentially, swapping out a system stream could cause unexpected and inconsistent failures.
IMO the best way to test the main method is by having the main method do absolutely nothing but set up the world and kick it off. This way one simple integration test gives the answer "has the world been set up".
Then all the other questions become much easier to answer.
The main method calls different methods for different console inputs and it calls different function for different arguments.
It should not, it should call someService.somemethod(args). This service gets tested like any other.
So i want to test this main method with Junit by mimicking these inputs from a file. how can i do it?
Either some form of fakes injected in or the use of the TemporaryFolder JUnit rule.
You can call main method from junit test like this:
YourClass.main(new String[] {"arg1", "arg2", "arg3"});
But since main method is void and does not return anything, you should test object that changed after main invocation;
Here is Link How do I test a method that doesn't return anything?
I'm using Mockito in my JUnit tests. The test is an integration test, testing a whole scenario, thus there are many assertions and verify(mock)s in it.
My problem is, that I'm writing some production code, doing some assertions and then verify the mock which works, until there is an identical mock invocation. see the simplified code:
interface I {
void m1();
void m2();
}
// some decorator
class T implements I {
public T(I decorated) {
/*...*/
}
/* ... */
}
public void testInvalid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
t.m2();
assertEquals("m2", t.getLastMethod());
verify(m).m2();
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m).m1();
// TooManyActualInvocations t.m1(): Wanted 1 time, but was 2 times ...
}
public void testValid() {
I m = mock(I.class);
T t = new T(m);
t.m1();
assertEquals("m1", t.getLastMethod());
t.m2();
assertEquals("m2", t.getLastMethod());
t.m1();
assertEquals("m1", t.getLastMethod());
verify(m, times(2)).m1();
verify(m).m2();
}
One idea is to verify the mocks at the end, but let's say there is a small stupid implementation mistake which leads to invoking the method m1 twice and m2 once but not as I would expect it in testInvalid but in the end the test would pass. I want my test to fail early. How do I accomplish that?
Thank you.
Thanks to #Woozy Coder:
Didn't mentioned, that reset would also be an option, but since it has to be called between verify and the next equal stub call, it makes it hard to write "nice" and correct tests, I think. There should be two different mocking styles:
"postcondition" mocking as Mockito does it
"early" mocking which would be an implicit reset after a verify-block
something like:
earlyReset(m).after(
new Runnable() {
t.someMethodInvokingTwoStubs();
verify(m).someMethod1();
verify(m).someMethod2();
}
);
I am having a similar problem and decided to use clearInvocations() (arrived in Mockito 2.1)
https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html#clearInvocations-T...-
Using reset() has the drawback that you loose your stubbing as well, clearInvocations() only clears the invocations.
Mockito was written to avoid brittleness, such that verification can make the least-specific assertion possible to allow for implementations to evolve without changing the test. If it doesn't matter to your test system that you're calling these methods multiple times, then you shouldn't ask Mockito to check it.
Alternatives:
Use atLeast or atLeastOnce to ensure the call happened at all without worrying how many additional times the method is called.
If the call is stubbed to have return values, infer that the system works from state assertions about the data you've stubbed.
If you really need stub or verification behavior to change across a single test method, your mock may grow outside the scope of what Mockito does well. Use an Answer for a single method, or write a manual Fake that simulates the interconnected methods properly.
I have some code like this:
class FooBar {
private String stateFoo;
public FooBar(String stateFoo){
this.stateFoo = stateFoo;
}
public void foo() {
FooInst f = FooInstFactory.createSomeFooInst(AnotherStaticFooConfig.getSomePath);
f.justCountMe();
}
}
My goal is to make sure that f.justCountMe() was executed exactly once. I know how to do it in general with mockito.
What I don't know is how do I inject a mocked version of FooInst into the foo method? So that I can count the invocation?
Is it even possible to do so?
You need to use powermockito and mock static method. See explanation how to do this here
PowerMockito mock single static method and return object
If possible; I suggest to avoid using mocking libraries that temper with static fields (in the way PowerMock/Mockito do) - as it often comes with undesired side effects (for example many "coverage" tools produce invalid results when static mocking takes places).
So my suggestion: re-design your class under test. Instead of fetching f from a static factory; provide a constructor for either the factory or f; then you can mock the corresponding object; without the need to turn to the mighty but dangerous "Powerxyz" stuff.
class Elephant extends Animal {
public Elephant(String name) {
super(name);
}
void makeNoise() {
logger.info(" Elephant make Sound");
}
void perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
makeNoise();
}
}
}
Now i want to test the perform method. How can I unit test this method using JUnit?
Solution with Mockito Spy
import org.junit.Test;
import static org.mockito.Mockito.*;
public class ElephantTest {
#Test
public void shouldMakeNoise() throws Exception {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("friday");
//then
verify(elephant).makeNoise();
}
}
Negative tests:
#Test
public void elephantShouldDontMakeNoisesOnMonday() {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("monday");
//then
verify(elephant, never()).makeNoise();
}
or
#Test
public void shouldDoNotMakeNoisesOnMonday() {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("monday");
then(elephant).should(never()).makeNoise();
}
Dependency
org.mockito:mockito-core:2.21.0
Read about
Mockito#doNothing()
Mockito#spy(T)
void() functions change the state of a program. This can be done by modifying a variable, a file, a database, etc.
In your case you're writing to a logger. If this results in writing " Elephant make Sound" to a file then you can read that file and see if the data in the file includes your noisy elephant.
If it however doesn't involve anything you can check (i.e.: it simply displays the output on the console) then you might want to look at some form of dependency injection (DI) where you can set the output to a file or something else you can easily read.
It should be noted that you can bypass DI by mocking the object and checking the appropriate methods are getting called.
To test any method, the responsibility to be tested must be visible from the out side of the method by changing state of any variable.
Typically it is done by returning value from the method. But without that, it can be done in many ways by modifying something from outside of the method scope, in case you have any "problem" to return something from the method!
In your case, you only log some message. And your code is not really testable in a sense that it does not do something that is directly related to changing the state of any variable (Because you change the state of other resource other than variable, that is not directly accessible by your code. You have to write some code to read the changes from that external resource, hence makes your testing code dependent to the reading also. If you have some problem with reading, your test case will not pass and that does not go with the spirit of the unit testing. The main idea is to reduce the dependency on external codes or libraries as much as possible). But your code can be testable by doing a slight refactoring / shifting responsiblity like below:
String makeNoise() {
return "Elephant make Sound";
}
String perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
return makeNoise();
}
}
And then you shift the responsibility of logging the value returned from perform method to the one using it like below:
logger.info(perform(day));
You have various options depending on the tools you are willing to use and the depth your tests should have.
Partial Mocking with plain Java
Create a class (MockElephant) that extends from elephant, overwrite makeNoise so it counts the number of invocations. Use that class in your test to check that makeNoise was called the correct number of times
Partial Mocking with a Framework
You basically do the same as above but instead of manually coding the MockElephant you create it using some mocking framework. Makes the test much simpler, since you need less code. And it is easier to read. But if strange things happen it makes it harder to understand what is going on. In case of Mocking frameworks I think they are worth it.
The reasons why this is called Partial Mocking is that you mock only parts of a class (a single method in this case).
The alternative is to use Normal Mocks, which in your case seems feasible (but can become tough in legacy code).
Here you would inject the Logger as a dependency. For example you could create an additional constructor which allows you to provide the Logger. In your test you would then use a mocked Logger, which again counts it's invocations, probably along with the parameter it received and check that it has the expected values.
Again you can do that with a Mocking Framework or with plain old Java.