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.
Related
I'm trying to work out how to verify the parameters passed to a mocked constructor in Mockito. A simplified version of my code is:
class Mocked {
Mocked(String first, String second, int value) {
}
}
class Target {
void testMe() {
new Mocked("Hello", "World", 99);
}
}
#Test
public void test_Target() {
try (
MockedConstruction<Mocked> mockedNew = mockConstruction(Mocked.class);
) {
new Target().testMe();
Mocked mocked = mockedNew.constructed().get(0);
// TODO: verify all arguments passed to mocked
}
}
The class I'm trying to test is "Target"
Target uses an instance of the "Mocked" class. In real code code I'll want to use an actual instance of Mocked, but for the purposes of testing I want to mock it out so I can test "Target" in isolation of "Mocked". I've used the mockConstruction construct to do this.
In my final version of my code the arguments passed to the Mocked constructor are not hardcoded. Instead there will be some business logic to derive them, so and I want to verify they have been derived out correctly. But how?
None of the examples I've Googled show show me how to do this, and org.mockito.Mockito.verify() doesn't appear to have a way to test a constructor.
The only solution I can see is to add mock initialiser function that copies the argument into local variables. But this involves making those variables effectively final (so final one element array) and ugly casts. Surely there has to be something better than that!
What have I missed?
As far as I know, this is not possible using the Mockito API.
You can try a design change where a new MockedFactory class is responsible for creating Mocked objects. You can create a MockMockedFactory for your tests and inject it into Target to use. You will be able to verify the methods called on this factory by the class under test. Not the nicest, adds boilerplate code, but works.
Also, I guess the newly created object is not returned as testing would not be a problem then. It is worth considering if the method you are testing isn't too big doing too many things at once. Maybe some other refactors could help make it more testable.
Or maybe this one: https://groups.google.com/g/mockito/c/WqPlcNrvbOw?pli=1
I'm fairly new to unit testing and have been reading a lot of material online, but I'm having a little trouble figuring stuff out.
For example: If I have the following piece of code :
public class RandomClass
{
int a = 4;
public void foo(Object obj)
{
if(a == 4)
{
AnotherObject anotherObj = new AnotherObject();
anotherObj.setAttribute(obj.getFiled());
//Method call that will be suppressed
Anotherclass.anotherMethod(anotherObj);
}
}
}
I thought of writing my junit test case like this:
#Test
public void testFoo()
{
int a=4;
RandomClass randomClass = new RandomClass();
Object object = new Object();
object.setField("hey");
randomClass.foo(object);
}
I have a couple of questions here.
How exactly do I set the integer a from my junit? The way I'm setting it right now doesn't the unit test case any impact. When I debug the unit test, the value of a is NULL so it never passes the if condition!
Also, the method foo returns a void so what can I possibly test/assert?
There are two major techniques when writing unit tests:
Checking the external contract of your class under test. Meaning: you try to write testcases for RandomClass that know nothing about AnotherClass. Instead, your test code only observes behavior of RandomClass objects. In other words: you really don't care about the internal implementation details of RandomClass - because all the things you "want to see" can be observed by checking what RandomClass objects return when you call methods with specific parameters. Occasionally you get there by adding (package protected) getter methods that allow you to inspect some internal state of your class under test.
But sometimes that might not be "good enough"; for example when you know that your class under test must be using some other objects to get its job done. In such situations, you should be looking into mocking objects. In your case, you might want to create a mocked instance of AnotherClass; and then you would use dependency injection in order to provide that object to your class under test.
You see, you actually wrote "hard to test" code - because you are calling new for AnotherClass in your production code. That doesn't seem like a big deal, but depending on what AnotherClass is about ... you really shouldn't do that!
In any case; I recommend you to look into these videos to learn how to write code that works better for unit testing.
A test normally starts with a "setup", "prepare", or "arrange" step, where it creates or modifies the object under test so that it is in the state needed by that particular test.
So, if field a in the RandomClass object needs to have a value 4 (for example), then the test needs to either create the object passing this value as a constructor argument, or to set the value in the object by calling a setter method or by directly accessing the field. In the worst case, you might need to use Reflection to set the field, but that would indicate a design issue in the class being tested.
The next step is to exercise the code under test. This is the "act" step, in the "Arrange, Act, Assert" terminology (AAA, for short).
Finally, the final step is to "assert" (verify) the code being tested did what is was supposed to do.
If the method being tested has void return type, then the test should verify it did what was expected either through state verification or through behavior verification.
In the first case, the test would call some getter method in the object under test, and use it in an "assert" of some kind (for example, an assertEquals(expectedValue, actualValue)).
In the second case, the test would use some mocking library in order to verify that expected calls were made from the code under test to one or more dependencies (other objects or classes on which the class under test depends). For example, here the test could verify that RandomClass#foo did actually call Anotherclass.anotherMethod(...).
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 want to test a method which internally calls a void method.
Below is the code
public String process(MKSConnectionParams mksConnectionParam, IProgressMonitor progressMonitor) throws Exception {
if (null != progressMonitor) {
progressMonitor.beginTask("Starting the creation of report", 100);
}
if (null == mksConnectionParam) {
initialize(MksLibFactory.getDefault());
}
else {
initialize(mksConnectionParam, MksLibFactory.getDefault());
}
--------------
}
public void initialize(MKSConnectionParams mksConnectionParam, IMksLibrary mksLibDefault) throws Exception {
paramMKSConnectionParams = mksConnectionParam;
GlobalConstants.hostName = paramMKSConnectionParams.hostname;
GlobalConstants.port = String.valueOf(paramMKSConnectionParams.port);
try {
localISi = mksLibDefault.getSi(paramMKSConnectionParams);
localIIm = mksLibDefault.getIm(paramMKSConnectionParams);
}
catch (MksLibException | AuthenticationError e) {
throw e;
}
ProjectInfo prjInfo = localISi.getProjectInfo(pathToPj);
projRevCmd = prjInfo.getConfigPath().getConfigPath() + "#b=" + projectRevision;
}
I am writing mockito test case for process() method. Testing is getting failed when initialize(mksConnectionParam, MksLibFactory.getDefault()) is called. It is because in the process we are calling real mks connection and I am passing dummy user name and password.
We aren't able to mock this initialize method. Is there any way to do this?
Small pseudocode would be of great help.
Earlier I had initialize method as private. Would changing it to public make any difference?
There are several ways to test this scenario, and different people would advocate different approaches, mostly based on personal preference.
Notice that testing this, will require changes in the code of the class you're testing (I believe you neglected to mention its name). There is one exception, and that's if you're using PowerMock. I won't go into the details here, but you find out more on how to incorporate it into your mockito code here.
Back to regular testing methods, the problem is that you're using the real IMksLibrary instead of a mock, and that's because you obtain a reference to it inside the process method. Here are a few method that you might want to consider:
Change the signature of the process method to receive the reference to the IMksLibrary instance, so that the test code can supply a mock of it
Instead of creating the reference inside the process method inject a reference to the class, either by using some DI framework (e.g. Spring, Guice, CDI, etc.), or as a constructor parameter
Create a protected method called something like getIMjsLibraryInstance() in the class, that will return MksLibFactory.getDefault(), and use it instead of the explicit code (this is the Extract Method refactoring that can be automatically done by most IDEs for Java nowadays). In the test code, you need to create a subclass (this is why it's my least favorite method) which overrides this method and returns a mock, and test the subclass instead of the real class. Notice that this is the ONLY method that you should subclass
You might feel deterred from using the third method, since in effect, you're not really testing the class that you meant to test (but rather a subclass of it). I tend to agree that this has a bed smell to it. However, keep in mind, that unlike the other two methods, this will not require any changes to the clients of the class (this is a pretty strong argument in favor of it).
There are other methods that you can use, but they are pretty similar in nature to the first two methods, and they also require some changes in the code.
If you feel that any "regular" method of testing is not good enough (due to code changes or whatever other reason), you are welcomed to take a look at PowerMock, which will enable you to intercept the static method call that returns the IMksLibrary instance, and return a mock instead. A word of caution though. There are some serious coupling that happens when these type of solutions are used, so it is usually not highly recommended, unless you are really in a dire need.
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.