springboot mockito JUnit 5 Command builder pattern service unit test - java

I'm writing the unit test to code that I wrote for a service class. Here is the short part of my class for the question(s) I have:
public interface Command { public void execute(); }
public class MyServiceClass {
private void doBusinessLogicValidation() {...}
private void doBusinessLogicValidation2() {...}
public void myMethod() {
doBusinessLogicValidation();
doBusinessLogicValidation2();
Command myCommand = callPrivateMethodToCreateMyCommand();
myCommand.execute();
}
private Command callPrivateMethodToCreateMyCommand() {
MyObject commandObject = MyObject.builder().add("something").additional("else").build();
return commandObject;
}
}
The above code is fine and works w/ no problem and uses Java access modifiers correctly: short and concise. For the unit test, I need to override the callPrivateMethodToCreateMyCommand, but it is (correctly) private. PowerMock does not support JUnit 5.
I can change the callPrivateMethodToCreateMyCommand() to public and easily use JUnit's when()...thenReturn() semantics. BUT that breaks encapsulation and the reason why one would use private. And do not want to use protected.
My unit of test is the MyServiceClass and NOT into the execute() method of myCommand. What am I missing?
Any help would be appreciated.
Thanks,Jim

Related

How to remove jMockit Fake/MockUp for abstract method?

Because I can't fake an abstract class directly and I know the implementing class, I added the fake to the implementing class.
#BeforeClass
public static void fakeCurrentYear() {
// Mocking the abstract 'Calender' does not work, see: https://github.com/jmockit/jmockit1/issues/71
// So we use the implementing class 'GregorianCalendar'.
new MockUp<GregorianCalendar>() {
#Mock public int get(Invocation invocation, int field) {
return 2016;
}
};
}
I'm using jMockit v 1.31 with JUnit 4.12 and Maven 3.x.
When I execute tests individually, everything is fine.
But when I execute all tests together, another test fails because the log4jlogger in the implementing class obviously uses the fake-implementation.
I think this is because previously GregorianCalendar did not overwrite that method. However, I thought the fake is automatically removed after the testclass! Is this a bug?
Can I remove it manually? I've tried stepping back to JMockit v1.25, created a static variable yearMock = new MockUp<GregorianCalendar>() ... and calling yearMock.tearDown() in a #AfterClass method, but it didn't change anything.
I've used a workaround, where I created a method in the class under test with just a single line of code
private int currentYear4digits() {
return Calendar.getInstance().get(Calendar.YEAR);
}
In my test I then mocked this method.
#BeforeClass
public static void fakeCurrentYear() {
new MockUp<MyClass>() {
#Mock
public int currentYear4digits() {
return 2016;
}
};
}
However, this is just a workaround. It would be cumbersome if the calls to Calendar where made from several classes.

How to include private contructor in Line Coverage?

I am using jmockit to mock my classes for unit test purpose. Everything is working fine so far.
I have a factory which is thread safe and singleton as shown below:
So for below class, I am able to get 50% Line Coverage because I am not able to cover private constructor TestFactory().
public class TestFactory {
// not able to cover this
private TestFactory() {}
private static class TestHolder {
private static final TestClient INSTANCE = new TestClient();
}
public static IClient getInstance() {
return TestHolder.INSTANCE;
}
}
My question is - Is there any way I can cover TestFactory() private constructor so that I can get 100% Line Coverage in my Cobertura Report for this class?
Invoke it using reflection or just mockit.Deencapsulation.newInstance(). Write a test method like this
#Test
public void privateConstructorCoverage() throws Exception {
Deencapsulation.newInstance(TestFactory.class);
}
Deencapsulation javadoc
Provides utility methods that enable access to (ie "de-encapsulate") otherwise non-accessible fields, methods and constructors belonging to code under test.

How to reuse existing JUnit tests in another test class?

how can I reuse JUnit tests in another testclass?
For example:
public TestClass1 {
#Test
public void testSomething(){...}
}
public TestClass2 {
#Test
public void testSomethingAndSomethingElse() {
// Somehow execute testSomething()
// and then test something else
}
}
Avoid the scenario, in general. It is prone to making tests much more brittle. If TestClass1 fails, then TestClass2 implicitly fails, which isn't desirable for at least the following reasons:
Code is tested more than once, which wastes execution time.
Tests should not rely on each other, they should be as decoupled as possible
If this becomes a pattern, it will become harder to identify what section of code is broken by looking at which tests are failing, which is part of the point of tests
Occasionally sharing sections of test code is useful, particularly for integration tests. Here's how you might do it without depending on the tests themselves:
public abstract BaseTests {
protected void somethingHelper() {
// Test something
}
}
public TestClass1 extends BaseTests {
#Test
public void testSomething(){
somethingHelper();
}
}
public TestClass2 extends BaseTests {
#Test
public void testSomethingAndSomethingElse() {
somethingHelper();
// and then test something else
}
}
Alternatively, you could use a helper class and avoid the inheritance altogether. Asserts and the like can go in the somethingHelper() method.
Don't call a method from TestClass1 in TestClass2 directly. The test cases become less readable this way, and can lead to spaghetti frittata.
As usual you can:
Extends TestClass2 from TestClass1
Access TestClass1 from TestClass2 using delegation:
Example 1:
// Instantiate TestClass1 inside test method
public TestClass2 {
public void testSomethingAndSomethingElse1() {
new TestClass1().testSomething();
}
}
Example 2:
// Instantiate TestClass1 as a member of TestClass2
public TestClass2 {
private TestClass1 one = new TestClass1();
public void testSomethingAndSomethingElse1() {
one.testSomething();
}
}
This is common to run a test with a different configuration. Do not worry about and go ahead.
At the first step create your own test without considering any configuration:
public abstract BaseTests {
#Test
protected void somethingHelper() {
// Test something
}
}
Then, extend the test class and add some configuration:
public TestClass1 extends BaseTests {
#Before
public void setup(){
// TODO: config
}
}
It is not necessary to do specific configuration but it is very common with a configurable system (the main functionality of the system must be valid for each config).
In the other test case:
public TestClass2 extends BaseTests {
#Before
public void setup(){
// TODO: other config
}
}
For example, there may be an encryption and decryption process where the sequence of encryption>decryption must be identified. On the other hand, there is a different algorithm to use while the test process is unique.
Logically, there is no reason to call one test method from another. Any tool that runs one test would just as easily all tests in the package. But if you need to, you'd call it like any other method in any other class.
What you most likely want to do, is perform some common setup for both test methods. You could put that code in a utility method in a common class, and invoke the common code in both tests.

Mocking a class object using Mockito and PowerMockito

Is it possible to mock a class object using Mockito and/or PowerMockito?
Something like:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
An alternative to mocking Class might be to use a Factory instead. I know you are concerned about refactoring, but this could be done without changing the public API of the class. You haven't provided much code to understand the class you are trying to test, but here's an example of refactoring without changing the API. It's a trivial class, but it might give you an idea.
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
Of course, the easiest thing to do to test this trivial class would be to use a genuine Runnable class, but if you tried to mock the Class, you would run into the problems you're having. So, you could refactor it thus:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
Now Instantiator does exactly the (trivially simple) thing it was doing before with the same public API and no need for any client of the class to do any special injecting of their own. However, if you wanted to mock the factory class and inject it, that's very easy to do.
why not using an agent if you can't refactor the code there isn't many options, as #jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.
However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.
The main idea is to modify your java command and add :
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :
#Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG is also supported. Just check the wiki page for more information.
Hope that helps.
First, as stated in the comments, you would need to do:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
Then you would do this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
#Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
How about this. creating a get method of the has a Object (MS) in class PCService and then mock it.
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
#Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}

jUnit - How to assert that inherited methods are invoked?

Let's say you have some 3rd-party library class that you want to extend, simply to add convenience methods to it (so you can call an inherited method with default parameters for example).
Using jUnit/jMock, is it possible to write an assertion / mock expection that tests that the correct inherited method is called?
For example, something like this:
class SomeClass extends SomeLibraryClass {
public String method(String code) {
return method(code, null, Locale.default());
}
}
How can I assert that method is being called?
You can make a further subclass inside your unit test that actually tells you:
public class MyTest {
boolean methodCalled = false;
#Test
public void testMySubclass(){
TestSomeClass testSomeClass = new TestSomeClass();
// Invoke method on testSomeclass ...
assertTrue( methodCalled);
}
class TestSomeClass extends SomeClass{
public String method(String code){
methodCalled = true;
}
}
}
Unit testing is more useful to verify the functionality of given methods, not to assert coverage. Unit tests that care more about what method got called know way more about the classes they are testing than they probably should, not to mention will be confusing to the reader.
Coverage tools like Cobertura or EMMA will tell you whether you properly covered your code.
It may indeed be better to only write integration tests in this case, but if you really want a unit test, you can have it just as easily as in any other case:
public class SomeClassTest
{
#Test
public void testMethod()
{
final String code = "test";
new Expectations()
{
SomeLibraryClass mock;
{
mock.method(code, null, (Locale) any);
}
};
new SomeClass().method(code);
}
}
This test uses the JMockit mocking API.
it's hard to tell without a more concrete example, but I'd guess that this ought to be an integration test--test the whole package together--rather than a unit test. Sometimes one can be too fine-grained with unit testing.

Categories

Resources