Testing for class field with is share among methods - java

I have a Java class as follow
public class MyClass {
private final ShowFactory showFactory;
private SomeShow someShow;
public MyClass(ShowFactory showFactory) {
this.showFactory = showFactory;
startShow();
}
public void startShow() {
someShow = showFactory.createShow();
someShow.start();
}
public void showSomething() {
MagicBox magicBox = new MagicBox();
someShow.showSomething(magicBox);
}
public void stopShow() {
someShow.stop();
}
}
and trying to test showSomething method. Complete test file is as follow
public class MyClassTest {
private ShowFactory showFactory;
private SomeShow someShow;
#Before
public void setUp() {
showFactory = mock(ShowFactory.class);
someShow = mock(SomeShow.class);
when(showFactory.createShow()).thenReturn(someShow);
}
#Test
public void shouldStartShow() {
new MyClass(showFactory);
verify(someShow).start();
}
#Test
public void shouldShowSomething() throws Exception {
MagicBox magicBox = mock(MagicBox.class);
PowerMockito.whenNew(MagicBox.class).withAnyArguments().thenReturn(magicBox);
doNothing().when(someShow).showSomething(magicBox);
InOrder inOrder = inOrder(someShow);
MyClass myClass = new MyClass(showFactory);
myClass.showSomething();
inOrder.verify(someShow).start();
inOrder.verify(someShow).showSomething(magicBox);
}
#Test
public void shouldStopShow() {
MyClass myClass = new MyClass(showFactory);
myClass.stopShow();
verify(someShow).start();
verify(someShow).stop();
}
}
But test shouldShowSomething is failing with error Wanted but not invoked. Any thing I am missing here? Any suggestion?

It was simple fix. After reading through https://github.com/powermock/powermock/wiki/MockConstructor#quick-summary (thanks to #roby) turns out I was missing the #PrepareForTest annotation for the class.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
...
}

Related

How to fully test coverage a constructor that has a System.getenv("name") operation inside

I am using JUNIT5, have been trying to fully coverage a piece of code that involves System.getenv(""); I writed a couple classes to replicate what I am experiencing right now and so you can use them to understand me also (minimal reproducible example):
First we have the service I need to get with full coverage (ServiceToTest.class) (it has a CustomContainer object which contains methods that it needs):
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest() {
Object configuration = new Object();
String envWord = System.getenv("envword");
this.customContainer = new CustomContainer(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}
CustomContainer.class:
public class CustomContainer {
#Getter
String containerName;
Object configuration;
public CustomContainer(Object configuration, String containerName) {
this.configuration = configuration;
this.containerName = containerName;
}
}
I have tried using ReflectionTestUtils to set the envWord variable without success... I tried this https://stackoverflow.com/a/496849/12085680, also tried using #SystemStubsExtension https://stackoverflow.com/a/64892484/12085680, and finally I also tried using Spy like in this answer https://stackoverflow.com/a/31029944/12085680
But the problem is that this variable is inside the constructor so this only executes once and I think that it happens before any of this configs I tried before can apply, here is my test class:
#ExtendWith(MockitoExtension.class)
class TestService {
// I have to mock this becase in real project it has methods which I need mocked behavour
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
// The serviceToTest class in which I use ReflectionTestUtils to use the mock above
// Here is where the constructor gets called and it happens BEFORE (debuged) the setup method
// which is anotated with #BeforeAll
private static ServiceToTest serviceToTest = new ServiceToTest();
#BeforeAll
static void setup() {
// set the field customContainer at serviceToTest class to mockCustomContainer
ReflectionTestUtils.setField(serviceToTest, "customContainer", mockCustomContainer);
}
#Test
void testGetContainerNameNotNull() {
assertNull(serviceToTest.getContainerName());
}
}
I need to write a test in which serviceToTest.getContainerName is not null but the real purpose of this is to have coverage of this sentence envWord == null ? "default" : envWord so it would be a test that is capable of executing the constructor and mocking System.getenv() so that it returns not null...
Right now the coverage looks like this and I can not find a way to make it 100% Any ideas??
EDIT:
So after following tgdavies suggestion, the code can be 100% covered, so this is the way:
Interface CustomContainerFactory:
public interface CustomContainerFactory {
CustomContainer create(Object configuration, String name);
}
CustomContainerFactoryImpl:
#Service
public class CustomContainerFactoryImpl implements CustomContainerFactory {
#Override
public CustomContainer create(Object configuration, String name) {
return new CustomContainer(configuration, name);
}
}
EnvironmentAccessor Interface:
public interface EnvironmentAccessor {
String getEnv(String name);
}
EnvironmentAccessorImpl:
#Service
public class EnvironmentAccessorImpl implements EnvironmentAccessor {
#Override
public String getEnv(String name) {
return System.getenv(name);
}
}
Class ServiceToTest after refactoring:
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest(EnvironmentAccessor environmentAccessor, CustomContainerFactory customContainerFactory) {
Object configuration = new Object();
String envWord = environmentAccessor.getEnv("anything");
this.customContainer = customContainerFactory.create(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}
Finally the test case after refactoring (here is were I think it can be improved maybe?):
#ExtendWith(MockitoExtension.class)
class TestService {
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
private static CustomContainerFactory customContainerFactoryMock = mock(CustomContainerFactoryImpl.class);
private static EnvironmentAccessor environmentAccessorMock = mock(EnvironmentAccessorImpl.class);
private static ServiceToTest serviceToTest;
#BeforeAll
static void setup() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn("hi");
serviceToTest = new ServiceToTest(environmentAccessorMock, customContainerFactoryMock);
ReflectionTestUtils.setField(serviceToTest, "customContainer", mockCustomContainer);
when(serviceToTest.getContainerName()).thenReturn("hi");
}
#Test
void testGetContainerNameNotNull() {
assertNotNull(serviceToTest.getContainerName());
}
#Test
void coverNullReturnFromGetEnv() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn(null);
assertAll(() -> new ServiceToTest(environmentAccessorMock, customContainerFactoryMock));
}
}
Now the coverage is 100%:
EDIT 2:
We can improve the test class and get the same 100% coverage like so:
#ExtendWith(MockitoExtension.class)
class TestService {
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
private static IContainerFactory customContainerFactoryMock = mock(ContainerFactoryImpl.class);
private static IEnvironmentAccessor environmentAccessorMock = mock(EnvironmentAccessorImpl.class);
private static ServiceToTest serviceToTest;
#BeforeAll
static void setup() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn("hi");
when(customContainerFactoryMock.create(any(), anyString())).thenReturn(mockCustomContainer);
serviceToTest = new ServiceToTest(environmentAccessorMock, customContainerFactoryMock);
}
#Test
void testGetContainerNameNotNull() {
assertNotNull(serviceToTest.getContainerName());
}
#Test
void coverNullReturnFromGetEnv() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn(null);
assertAll(() -> new ServiceToTest(environmentAccessorMock, customContainerFactoryMock));
}
}
Refactor your code to make it testable, by moving object creation and static method calls to components, which you can mock in your tests:
interface ContainerFactory {
CustomContainer create(Object configuration, String name);
}
interface EnvironmentAccessor {
String getEnv(String name);
}
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest(ContainerFactory containerFactory, EnvironmentAccessor environmentAccessor) {
Object configuration = new Object();
String envWord = environmentAccessor.getEnv("envword");
this.customContainer = containerFactory.create(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}

Mockito problems and says undefinied type while ı am testing my service

I am writing unit test but I am facing an error some how. I am triyng to test my ServiceImpl just showing my entire code down below My code below;
My Service Class
#Service
public class PlaneServiceImpl implements PlaneCallerService {
private final PlaneFactory planeFactory;
public PlaneServiceImpl(PlaneFactory planeFactory) {
this.planeFactory = planeFactory;
}
#Override
public String getPlaneType(String planeType) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(planeFactory.getPlane(planeType).getType());
stringBuilder.append(" Plane has produced.");
return stringBuilder.toString();
}
Plane class down below
public interface Plane {
String getType();
}
My PlaneFactory class down below;
#Component
public class PlaneFactory {
public Plane getPlane(String planeType) {
if (StringUtils.isBlank(planeType)) {
throw new PlaneTypeNotFoundException();
}
if (planeType.equalsIgnoreCase("lightJet")) {
return new LightJet();
} else if (planeType.equalsIgnoreCase("midJet")) {
return new MidJet();
My Mock Test just down below
public class PlaneCallerServiceImplTest {
private PlaneFactory planeFactory;
private PlaneCallerService planeCallerService;
private plane plane;
#Before
public void setUp() {
planeFactory = mock(PlaneFactory.class);
planeCallerService = new PlaneCallerServiceImpl(planeFactory);
plane= mock(Plane.class);
}
#Test
public void testPlaneType() {
String planeType = "";
when(planeFactory.getPlane(planeType)).thenReturn(plane);
String result = planeCallerService.getplaneType(planeType);
assertNotNull(result);
}
}
I'm getting The method getPlane(String) is undefined for the type PlaneFactory
I am quite new for unit test and also mock test any help would be appreciate
Thank you in advanced
Your issue is that from the below statement:
when(planeFactory.getPlane(planeType)).thenReturn(plane);
you are returning a mocked response of type Plane but in that mocked response when you call Plane.getType() that method is not implemented.
You can mock the response of that too, add
when(plane.getType()).thenReturn("SOME_MOCKED_STRING");
This should start to work.
Below is the complete test class:
public class PlaneServiceImplTest {
private PlaneFactory planeFactory;
private PlaneServiceImpl planeCallerService;
#Before
public void setUp() {
planeFactory = mock(PlaneFactory.class);
planeCallerService = new PlaneServiceImpl(planeFactory);
}
#Test
public void testPlaneType() {
Plane plane = mock(Plane.class);
when(planeFactory.getPlane(anyString())).thenReturn(plane);
String result = planeCallerService.getPlaneType("Test");
assertNotNull(result);
}
}

Repeat JUnit tests run with different setup

For example I have some tests based on Set<Integer>. I want to run them with TreeSet and then with HashSet. Can I do it without manual initialization inside test method body?
Something like this:
public class SomeTest {
Set<Integer> set;
#Before
public void init() {
set = new HashSet<>();
}
// #Before
// public void init2() {
// set = new TreeSet<>();
// }
//test...
}
I want to run all tests with init() first and then with init2(). How can I do it?
A cleaner approach would be:
public abstract class SomeTestsForSets {
Set<Integer> set;
#Before
public abstract void init();
//test cases...
}
public class HashSetTests extends SomeTestsForSets {
#Override
public void init() {
this.set = new HashSet<>();
}
}
public class TreeSetTests extends SomeTestsForSets {
#Override
public void init() {
this.set = new TreeSet<>();
}
}

Jmockit and #PostConstruct bean

I have created a bean with method that I want to test. Unfortunately it's a bean with a PostConstruct annotation in it. I don't want to call the PostConstruct method.
How can I do this?
I've tried 2 different ways (as shown in the example below) but none working; init() still gets called.
Can someone please give me a detailed example of how to do this?
DirBean.java
#Singleton
#Startup
public class DirBean implements TimedObject {
#Resource
protected TimerService timer;
#PostConstruct
public void init() {
// some code I don't want to run
}
public void methodIwantToTest() {
// test this code
}
}
MyBeanTest.java
public class MyBeanTest {
#Tested
DirBean tested;
#Before
public void recordExpectationsForPostConstruct() {
new Expectations(tested) {
{
invoke(tested, "init");
}
};
}
#Test
public void testMyDirBeanCall() {
new MockUp<DirBean>() {
#Mock
void init() {
}
};
tested.methodIwantToTest();
}
}
MyBeanTest2.java (WORKS)
public class MyBeanTest2 {
#Tested
DirBean tested;
#Before
public void recordExpectationsForPostConstruct() {
new MockUp<DirBean>() {
#Mock
void init() {}
};
}
#Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}
MyBeanTest3.java (WORKS)
public class MyBeanTest3 {
DirBean dirBean = null;
#Mock
SubBean1 mockSubBean1;
#Before
public void setupDependenciesManually() {
dirBean = new DirBean();
dirBean.subBean1 = mockSubBean1;
}
#Test
public void testMyDirBeanCall() {
dirBean.methodIwantToTest();
}
}
MyBeanTest4.java (FAILS with NullPointerException on invoke())
public class MyBeanTest4 {
#Tested
DirBean tested;
#Before
public void recordExpectationsForCallsInsideInit() {
new Expectations(tested) {
{
Deencapsulation.invoke(tested, "methodCalledfromInit", anyInt);
}
};
}
#Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}
Move definition of MockUp type to #Before method:
public class MyBeanTest {
#Tested
DirBean tested;
#Before
public void recordExpectationsForPostConstruct() {
new MockUp<DirBean>() {
#Mock
void init() {
}
};
}
#Test
public void testMyDirBeanCall() {
tested.methodIwantToTest();
}
}

Function works in main class but not it test class

I have a class which compiles and runs as expected (adds one test node per execution):
public class ReqsDb {
private final String STORE_DIR;
public GraphDatabaseService graphDb;
private static enum RelTypes implements RelationshipType {
IDENTIFIES, SATIFIES
}
public ReqsDb(String dbPath) {
STORE_DIR = dbPath;
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(STORE_DIR);
registerShutdownHook(graphDb);
}
public void createTestNode() {
Transaction tx = graphDb.beginTx();
Node newNode;
try {
newNode = graphDb.createNode();
newNode.setProperty("test", "test");
tx.success();
} finally {
tx.finish();
}
}
private static void registerShutdownHook(final GraphDatabaseService graphDb) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
graphDb.shutdown();
}
});
}
void shutDown() {
graphDb.shutdown();
}
public static void main(String[] args) {
ReqsDb testDb = new ReqsDb("target/testDb");
testDb.createTestNode();
}
}
However the test function, testCreateTestNode() causes error:
java.lang.RuntimeException: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.kernel.StoreLockerLifecycleAdapter#4e3a2be1' was successfully initialized, but failed to start.
Since the function works as called from main(), I think there is something wrong with the test class.
package com.github.dprentiss;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class ReqsDbTest extends TestCase {
protected ReqsDb testDb = new ReqsDb("target/testDb");
public ReqsDbTest(String testName) {
super(testName);
}
public static Test suite() {
return new TestSuite(ReqsDbTest.class);
}
public void testDbService() {
assertNotNull(testDb);
}
public void testCreateTestNode() {
testDb.createTestNode();
}
public void tearDown() {
testDb.shutDown();
}
Is there something wrong with my test set up?
Try to put
protected ReqsDb testDb = new ReqsDb("target/testDb");
in an init method . Follow this example:
Is there a basic template I can use to create a test?

Categories