AssertionFailedError while Testing Component with Configuration via Properties - java

Hi. I have a service and a util classes as follows:
#Service
#RequiredArgsConstructor
public class DeviceService {
private final DeviceUtil deviceUtil;
public String getAllDevicesDeviceType(DeviceType deviceType){
final String appIdByDeviceType = deviceUtil.getAppIdByDeviceType(deviceType);
// ... actually I return smth different, but for simplicity just returning appIdByDeviceType
return appIdByDeviceType;
}
}
#Component
public class DeviceUtil {
private final String androidAppId;
public DeviceUtil(ApplicationProperties applicationProperties) {
ApplicationProperties.DeviceClient client = applicationProperties.getDeviceClient();
androidAppId = client.getAndroidAppId();
}
public String getAppIdByDeviceType(DeviceType deviceType) {
if (deviceType == DeviceType.ANDROID) return androidAppId;
throw InvalidInputException.of(ErrorCode.PARAMETER_INVALID, ErrorMessage.DEVICE_TYPE_INVALID);
}
}
In ApplicationProperties class I am getting static data from application.yml file. While running project, all are ok. But when I wrote a test for DeviceUtil class as follows:
#ExtendWith(MockitoExtension.class)
class DeviceUtilTest {
#Spy
private ApplicationProperties applicationProperties;
#InjectMocks
private DeviceUtil deviceUtil;
#Test
void getAppIdByDeviceType_Should_ReturnSuccess() {
String actualResult = deviceUtil.getAppIdByDeviceType(DeviceType.ANDROID);
assertNotNull(actualResult);
// assertThat(actualResult).isEqualTo(APP_ID);
}
}
Test failed with foloowing description:
expected: not null
org.opentest4j.AssertionFailedError: expected: not <null>
How can I solve the issue? Thanks in advance.

Related

Mock class with static method to execute test case in Springboot

Hi I have a class with static method as below
#Log4j2
#Profile("!ut")
#Component('CALC')
#ConditionalOnProperty(name = 'CALC', havingValue = 'VAL')
public class
ClassA extends ClassMain {
public static org.apache.logging.log4j.Logger narrLogger;
#Autowired
IHCRefDataMgr ihcRefDataMgr;
public ClassA(IHCRefDataMgr ihcRefDataMgr) {
super(ihcRefDataMgr);
this.ihcRefDataMgr = ihcRefDataMgr;
}
public boolean calculate(msg) {
narrLogger = Narratives.getNarrativeLogger(msg)
}
}
I have another class where i trace the logs
#Data
#Component
#ConditionalOnProperty(name = 'CALC', havingValue = 'VAL')
#Log4j2
public class ClassB {
Boolean prepareMap() {
Boolean status = true;
try {
Set<String> securityKeys = ConcurrentHashMap.newKeySet();
ClassA.narrLogger.trace("Security Keys for given BA: {}", securityKeys);
// doing some processing
} catch (Exception e) {
status = false;
System.out.println(e);
}
}
}
Now I want to write a test case for ClassB, In my debugger when I come to ClassA.narrLogger, i get null pointer exception. How can i mock ClassA and allow it to pass assuming i dont want to test narrLogger.
Test Case
#Log4j2
#SpringBootTest
#TestPropertySource(properties = {"spring.profiles.active=test,ut", "calculator.name = ClassA", "eureka.client.enabled = false"})
public class ClassBTest {
ClassB classb;
#Test
public void prepareMapTest() {
var status = classb.prepareMap();
Assertions.assertEquals(true, status)
}
}
While running test case, it falls in exception as null pointer comes at ClassA.narrLogger

How to mock model in service test?

I try write service test, for example, I have this ExamServiceImpl:
#Service
public class ExamServiceImpl implements ExamService {
#Autowired
private final SubjectService scoreService;
private final ScoreDAO scoreDAO;
#Autowired
public ExamServiceImpl(ScoreDAO scoreDAO) {
this.scoreDAO = scoreDAO;
}
#Override
public ResponseModel insertScore(RequestModel request) throws IOException {
SubjectModel subject = scoreService.getNameSubject(request);
ScoreModel score = new ScoreModel();
score.setStudentName(request.getStudentName);
score.setScore(request.getStudentScore);
score.setSubject(subject.getName);
int result = scoreDAO.insert(score);
return result;
}
}
Sample my test:
#SpringBootTest
public class ExamServiceImplTest {
#MockBean
private ScoreDAO scoreDAO;
#Autowired
private SubjectService subjectService;
#Autowired
private ExamService examService;
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
But output resultTest is 0. I try debugger, I found mock scoreDAO.insert() return 0 >> is not working.
And I try like this:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ExamServiceImplTest {
#Mock
private ScoreDAO scoreDAO;
#Mock
private SubjectService subjectService;
#InjectMocks
private ExamService examService = ExamServiceImpl(scoreDAO);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
Mockito.when(subjectService.getNameSubject(new RequestModel())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(new ScoreModel())).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
It's not work too.
Please, could you help write me test methods? I covered with tests more simple other services.
Thank you!
It doesn't work because new ScoreModel() inside Mockito.when() and inside ExamServiceImpl are two different objects. If you want scoreDAO to return 1 for every ScoreModel passed to it you can use:
Mockito.when(scoreDAO.insert(Mockito.any(ScoreModel.class)).thenReturn(1);

Java Unittest with Mockito NullPointer Exception Error

I'm trying to write a unittest (test_myMethod) for one of my methods (myMethod) but I can't seem to get it to work. I get a NullPointer exception error with the code below. In my test it seems that the line myClass.otherMethod("hostName") in the unittest evaluates to Null so it can't do .getOSRevision(). Anyone know how I can get my unittest to pass?
MyClass.java
public class MyClass {
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
OtherMethod response = myClient.newMyMethodRevisionCall().call(
someObject.builder()
.withHostName(hostname)
.build()
);
return response;
}
}
MyClassTest.java
public class MyClassTest {
#Mock
private MyClient myClient;
#Mock
private MyMethodRevisionCall myMethodRevisionCall;
#Mock
private OtherMethod otherMethod;
private MyClass myClass;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
myClass = new MyClass(myClient);
}
// My failing unittest attempt
#Test
public void test_myMethod() {
when(myClass.otherMethod("hostName")
.getOSRevision()) //java.lang.NullPointerException happens on this line.
.thenReturn("TestString");
final String result = myClass.myMethod("TestString");
verify(myMethodRevisionCall, times(1)
}
}
You cannot use Mockito.when() on classes that are not mocked by Mockito. MyClass is not a mock. Instead you create an actual instance of it. Therefore, you need to actually run the code and not mock it. However, all dependencies of your class under test (MyClient in your case) you can mock.
This is a working example:
public class MyClass {
private MyClient myClient;
public MyClass(MyClient myClient) {
this.myClient = myClient;
}
public String myMethod(final String hostname) {
return otherMethod(hostname).getOSRevision();
}
public OtherMethod otherMethod(final String hostname) {
return myClient.newMyMethodRevisionCall().call(new SomeObject(hostname));
}
}
class MyClassTest {
private MyClient myClient;
private MyClass myClass;
#BeforeEach
void setUp() {
myClient = mock(MyClient.class);
myClass = new MyClass(myClient);
}
#Test
public void test_myMethod() {
MyMethodRevisionCall myMethodRevisionCall = mock(MyMethodRevisionCall.class);
OtherMethod otherMethod = mock(OtherMethod.class);
when(myClient.newMyMethodRevisionCall()).thenReturn(myMethodRevisionCall);
when(myMethodRevisionCall.call(any())).thenReturn(otherMethod);
when(otherMethod.getOSRevision()).thenReturn("revision");
final String result = myClass.myMethod("TestString");
assertEquals("revision", result);
verify(myMethodRevisionCall, times(1));
}
}

How to inject value to a bean in spring test?

i have a question here, please give some ideas.
I have two beans. FaceComparisonServerImpl depends on FaceServer.
When i want to test. I want to change the String in my 'FaceServer' bean.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
#Autowired
private FaceServer faceServer;
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
...
}
}
#Component
public class FaceServer {
#Autowired
private RestTemplate restTemplate;
//Not final, just to test.
private String version = "1.0";
private static final String CODE = "code";
private static final String MESSAGE = "message";
//Final
private static final String SERVER_URL = "http://127.0.0.1:8066/api/ZKComparison";
}
Bellow is my test code.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
#Test
public void getServerInfo(){
//How can i modify the value of SERVER_URL in faceServer?
FaceComparsionInfo serverInfo = faceComparisonServer.getServerInfo();
System.out.println(serverInfo);
}
}
My question is:
How can i modified the value of 'version' and 'SERVER_URL' in #Bean(faceServer)?
Thanks you!
You need create FaceServer mock bean for test configuration.
And override required methods
#Configuration
Class TestConfig{
#Bean
#Primary
public FaceServer faceServer() {
return new FaceServer() {
#override
public String getServerInfo(){
return "required info";
}
};
}
}
The easiest way to customize the values is to make them Spring properties:
#Component
public class FaceServer {
#Value("${faceServer.version}")
private String version;
#Value("${faceServer.url}")
private String serverUrl;
// ...
}
You can either have default values for the #Value annotations or use some default property values in application.yml.
Now just override those properties in your test with the values you want:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
#TestPropertySource(properties = {
"faceServer.version=1.0",
"faceServer.url=http://127.0.0.1:8066/api/ZKComparison"
})
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
// ...
}
However...
The second option is to make your classes more unit-testable. Prefer construction injection over field injection, and you can test your classes more independently.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
private final FaceServer faceServer;
public FaceComparisonServerImpl(FaceServer faceServer) {
this.faceServer = faceServer;
}
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
// ...
}
}
This now becomes unit-testable:
public class FaceServerTestByTyler {
private FaceComparisonServer faceComparisonServer;
private FaceServer faceServer;
#BeforeEach
public setup() {
faceServer = mock(FaceServer.class);
faceComparisonServer = new FaceComparisonServer(faceServer);
}
#Test
public void getServerInfo() {
when(faceServer.getServerInfo()).thenReturn(xxx);
// ...
}
}
The second option ends up with a test that runs much faster than any solutions that suggest to create a mock bean through a test configuration.

Unable to call the function from the mocked component class

I have a junit test method as follows:
#SpringBootTest
public class StoreIdAssignmentServiceTest {
private static final Logger log = LoggerFactory
.getLogger(StoreIdAssignmentServiceTest.class);
#InjectMocks
private StoreIdAssignmentService storeIdAssignmentService;
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
#Mock
private DatabaseService databaseService;
#Test
public void rollUpFeed_Single_DealerAndStoreID_NoExisting() {
List<ScmsaPosTransRollup> scmsaPosTransRollupFeedList = new ArrayList<>();
ScmsaPosTransRollup posTransRollup = new ScmsaPosTransRollup();
posTransRollup.setJobLogId(8269726L);
posTransRollup.setDealerCode("3119255");
posTransRollup.setStoreId("9842");
posTransRollup.setTransactionDate(Timestamp
.valueOf("2018-03-01 13:00:00.00"));
posTransRollup.setQuantity(4);
posTransRollup.setRollupType("H");
scmsaPosTransRollupFeedList.add(posTransRollup);
Mockito.when(
databaseService.getUnProcessedRollUpFeedBasedonRollupType("H"))
.thenReturn(scmsaPosTransRollupFeedList);
List<PosHourlySt> existingPosHourlyStEntries = new ArrayList<>();
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
storeIdAssignmentService.processHourlyStateFeed();
assertNotNull(posHourlyStRepository.findAll());
}
}
And My StoreIdAssignmentService class will be:
#Service
public class StoreIdAssignmentService {
private StoreIdAssignmentFactory storeIdAssignmentFactory;
private DatabaseService databaseService;
#Autowired
public StoreIdAssignmentService(StoreIdAssignmentFactory storeIdAssignmentFactory,
DatabaseService databaseService) {
this.storeIdAssignmentFactory = storeIdAssignmentFactory;
this.databaseService = databaseService;
}
public void processHourlyStateFeed() {
.......................
calculateStateForPosHourlyStTransaction(posHourlyStToConsider, newPosHourlyStEntries);
.........
}
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = storeIdAssignmentFactory
.createUpdatedRollUpEntries(rollUpFeedByDealerCode);
saveAndUpdatePosHourlyStAndRollUpEntries(newPosHourlyStEntries, existingPosHourlyStEntries,
rollUpFeedByDealerCode, scmsaPosTransRollupUpdatedFlagList);
}
}
private Map<String, List<ScmsaPosTransRollup>> groupDealerCodeRollUpFeedByStoreId(
List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
// Grouping the rollUpFeedByDealerCode by storeID
return rollUpFeedByDealerCode.stream().collect(Collectors.groupingBy(ScmsaPosTransRollup::getStoreId));
}
private void calculateStateForPosHourlyStTransaction(ScmsaPosTransRollup scmsaPosTransRollupToConsider, List<PosHourlySt> newPosHourlyStEntries) {
List<PosHourlySt> posHourlyStList = newPosHourlyStEntries.stream().filter(
hourlyState -> (hourlyState.getStartDate().before(scmsaPosTransRollupToConsider.getTransactionDate())))
.collect(Collectors.toList());
..............
PosHourlySt posHourlySt=storeIdAssignmentFactory.createHourlyStEntryFromRollUp(scmsaPosTransRollupToConsider,
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(0).withMinute(0)),
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(23).withMinute(59)));
newPosHourlyStEntries.add(posHourlySt);
....................
}
}
and My Factory class would be:
#Component
public class StoreIdAssignmentFactory {
private static final Logger log = LoggerFactory.getLogger(StoreIdAssignmentFactory.class);
private ModelMapper modelMapper;
#Autowired
public StoreIdAssignmentFactory(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
public PosHourlySt createHourlyStEntryFromRollUp(ScmsaPosTransRollup scmsaPosTransRollup, Timestamp startDate, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(scmsaPosTransRollup.getDealerCode());
posHourlySt.setSourceJobLogId(scmsaPosTransRollup.getJobLogId());
posHourlySt.setStartDate(startDate);
posHourlySt.setStoreId(scmsaPosTransRollup.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("New Rec: {}", posHourlySt.toString());
return posHourlySt;
}
public PosHourlySt createHourlyStEntryFromPosHourlySt(PosHourlySt posHourlyStToSplit, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(posHourlyStToSplit.getDealerCode());
posHourlySt.setSourceJobLogId(posHourlyStToSplit.getJobLogId());
posHourlySt.setStartDate(posHourlyStToSplit.getStartDate());
posHourlySt.setStoreId(posHourlyStToSplit.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("SplitupRec: {}", posHourlySt.toString());
return posHourlySt;
}
public List<ScmsaPosTransRollup> createUpdatedRollUpEntries(List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = new ArrayList<>();
for(ScmsaPosTransRollup scmsaPosTransRollupFeed : rollUpFeedByDealerCode) {
ScmsaPosTransRollup scmsaPosTransRollupUpdateFlag = new ScmsaPosTransRollup();
modelMapper.map(scmsaPosTransRollupFeed, scmsaPosTransRollupUpdateFlag);
scmsaPosTransRollupUpdateFlag.setProcessedFlag("Y");
scmsaPosTransRollupUpdatedFlagList.add(scmsaPosTransRollupUpdateFlag);
}
return scmsaPosTransRollupUpdatedFlagList;
}
}
The StoreIdAssignmentService class contains the method "calculateStateForPosHourlyStTransaction" which calls some method in Factory class. When I debug as the junit test case , am not able to call that factory class method . What I am doing wrong here. Can anyone please suggest me.
You are mocking the factory:
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
So you can't investigate the method createHourlyStEntryFromRollUp inside the factory, because the whole factory is mocked:
storeIdAssignmentFactory.createHourlyStEntryFromRollUp
If you trying to debug the createHourlyStEntryFromRollUp and the StoreIdAssignmentFactory is a #Component (or #Service), I recommend create a StoreIdAssignmentFactoryTest class test, use the #Autowired on it and #MockBean his dependencies.
Example:
#SpringBootTest
public class StoreIdAssignmentFactoryTest {
#Autowired
StoreIdAssignmentFactory factory;
#Test
public void testing() {
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp(...);
//TODO asserts and etc
}
}
But this test is considered a integration test, because it load the whole spring context and beans related.
Another alternative is the (true) unit test. Use your constructor and not use #SpringBootTest, mock the dependencies (ModelMapper). This makes the test more fast and simple.
Example:
public class StoreIdAssignmentFactoryTest {
#Test
public void testing() {
ModelMapper mapper = mock(ModelMapper.class);
StoreIdAssignmentFactory factory = new StoreIdAssignmentFactory(mapper)
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp();
//TODO asserts and etc
}
}

Categories

Resources