Getting null pointer in static method Junit - java

I have following service
public UserActivityLog save(UserActivityLog userActivityLog){
LOGGER.debug("User activity save called.");
userActivityLog.setCreatedByUser(User.getUser().getUserId());
userActivityLog.setCreationTime(new Date());
return activityLogRepository.save(userActivityLog);
}
I had written following Junit for test this but getting null pointer for User
#RunWith(MockitoJUnitRunner.class)
public class ActivityHistoryServiceTest {
#InjectMocks
private ActivityHistoryService activityHistoryService;
#Mock
private ActivityLogRepository activityLogRepository;
#Test
public void testSave() {
UserActivityLog userActivityLog = new UserActivityLog();
/* Called some setter methods to set value here*/
UserProfile profile = new UserProfile();
Mockito.when(User.getUser()).thenReturn(profile);
Assert.assertNotNull(activityLogRepository.save(userActivityLog));
}
}
User class is like
public class User {
private User(){}
public static UserProfile getUser(){
/*some logic*/
return userProfile;
}
}
Please help for this. thanks in advance.

Static methods are useful when they are useful. Use them as a replace for singletons is not a very good practice. Instead of what you have your code could look like this:
public class MyClass {
private final Logger logger;
private final UserProvider userProvider;
private final DateProvider dateProvider;
/** Constructor that sets all attributes */
public MyClass(...) {...}
public UserActivityLog save(UserActivityLog userActivityLog){
LOGGER.debug("User activity save called.");
userActivityLog.setCreatedByUser(userProvider.get().getUserId());
userActivityLog.setCreationTime(dateProvider.get());
return activityLogRepository.save(userActivityLog);
}
}
Provider classes are quite simple. They just have a get() method that returns an instance of required type:
public class DateProvider {
public Date get() {
return new Date();
}
}
public class UserProvider {
public User get() {
...
}
}
With this setup you can easily mock the dependencies

You need PowerMock to mock the static methods.
Refer:
https://blog.codecentric.de/en/2016/03/junit-testing-using-mockito-powermock/

Related

Spring bean scope for "one object per test method"

I have a test utility for with I need to have a fresh instance per test method (to prevent that state leaks between tests). So far, I was using the scope "prototype", but now I want to be able to wire the utility into another test utility, and the wired instances shall be the same per test.
This appears to be a standard problem, so I was wondering if there is a "test method" scope or something similar?
This is the structure of the test class and test utilities:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTest {
#Autowired
private TestDriver driver;
#Autowired
private TestStateProvider state;
// ... state
// ... methods
}
#Component
#Scope("prototype") // not right because MyTest and TestStateProvider get separate instances
public class TestDriver {
// ...
}
#Component
public class TestStateProvider {
#Autowired
private TestDriver driver;
// ...
}
I'm aware that I could use #Scope("singleton") and #DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) but this refreshes more than I need – a new TestDriver instance for each test would be enough. Also, this approach is error-prone because all tests using the TestDriver would need to know that they also need the #DirtiesContext annotation. So I'm looking for a better solution.
It is actually pretty easy to implement a testMethod scope:
public class TestMethodScope implements Scope {
public static final String NAME = "testMethod";
private Map<String, Object> scopedObjects = new HashMap<>();
private Map<String, Runnable> destructionCallbacks = new HashMap<>();
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
public static class TestExecutionListener implements org.springframework.test.context.TestExecutionListener {
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) testContext
.getApplicationContext();
TestMethodScope scope = (TestMethodScope) applicationContext.getBeanFactory().getRegisteredScope(NAME);
scope.destructionCallbacks.values().forEach(callback -> callback.run());
scope.destructionCallbacks.clear();
scope.scopedObjects.clear();
}
}
#Component
public static class ScopeRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope(NAME, new TestMethodScope());
}
}
}
Just register the test execution listener, and there will be one instance per test of all #Scope("testMethod") annotated types:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestExecutionListeners(listeners = TestMethodScope.TestExecutionListener.class,
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public class MyTest {
#Autowired
// ... types annotated with #Scope("testMethod")
}
I ran into the same problem some time ago and came to this solution:
Use Mocks
I wrote some methods to create specific mockito settings to add behavior to each mock.
So create a TestConfiguration class with following methods and bean definition.
private MockSettings createResetAfterMockSettings() {
return MockReset.withSettings(MockReset.AFTER);
}
private <T> T mockClass(Class<T> classToMock) {
return mock(classToMock, createResetAfterMockSettings());
}
and your bean definition will look like:
#Bean
public TestDriver testDriver() {
return mockClass(TestDriver .class);
}
MockReset.AFTER is used to reset the mock after the test method is run.
And finally add a TestExecutionListeners to your Test class:
#TestExecutionListeners({ResetMocksTestExecutionListener.class})

How to get values from bootstrap.yml file from static instance

I have a classes CosmosConnection and SupplierGetResponseFeed
I am calling the method of CosmosConnection from SupplierGetResponseFeed
The method of SupplierGetResponseFeed from which I am calling CosmosConnection method is static
Example : public static SupplierResponseDataEntity prepareSupplierAzureData(Map<String, Object> row, String[] columnNames) {
So , When I create the object of CosmosConnection in SupplierGetResponseFeed I can not use #Autowired as a reason I am not able to pick the value from bootstrap.yml file in CosmosConnection
Though I create the object using #Autowired in SupplierGetResponseFeed I am not able to pick the values from bootstrap
#Autowired
static CosmosConnection cosmos;
Below is the code for SupplierGetResponseFeed
public class SupplierGetResponseFeed {
static CosmosConnection cosmos= new CosmosConnection(); //creating object
public static SupplierResponseDataEntity prepareSupplierAzureData(Map<String, Object> row, String[] columnNames) {
//Some code
cosmos.connectToDB(); //calling the method of CosmosConnection class
}
The code for is CosmosConnection
#Configuration
#ComponentScan
public class CosmosConnection {
#Value("${cosmos.connectionuri}") private String uri;
#Value("${cosmos.primarykey}") private String primarykey;
public String connectToDB() throws DocumentClientException, IOException, ParseException {
System.out.println("URI is " + uri); //getting this as null
What changes I need to do for picking the values from bootstrap.yml ??
A annotation called PostConstruct in package javax.annotation with spring framework can be used to solve the problem. As described in the source code:
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization
And code below is a example:
#Configuration
public class ComosConfig {
#Value("${cosmos.connectionuri}") private String uri;
#Value("${cosmos.primarykey}") private String primarykey;
//get and set methods here
}
public class CosmosConnection {
private String uri;
private String primaryKey;
public CosmosConnection(String uri, String primaryKey) {
this.uri = uri;
this.primaryKey = primaryKey;
}
public String connectToDB() {
//do something here
}
}
#Component
public class SupplierGetResponseFeed {
private static CosmosConnection cosmos;
private CosmosConfig config;
public SupplierGetResponseFeed(CosmosConfig config) {
this.config = config;
}
#PostConstruct
public void init() {
String uri = config.getUri();
String primaryKey = config.getprimaryKey();
cosmos = new cosmos(uri, primaryKey);
}
public static SupplierResponseDataEntity prepareSupplierAzureData() {
cosmos.connectToDB(); //calling the method of CosmosConnection class
}
}
After all, it's not recommended in view of code analysis utils to write to static from instance method, so you may need suppress-warning-annotation used with init method to eliminate warnings.

How do I inject dependencies in controller tests?

This is my class and its constructor and the dependencies.
public class FavouriteProfilesController extends BaseController implements CurrentUser, JsonHelper {
private final UserProvider userProvider;
private MessagesApi msg;
#javax.inject.Inject
public FavouriteProfilesController(
UserProvider userProvider,
MessagesApi msgApi) {
this.userProvider = userProvider;
this.msg = msgApi;
}
// methods etc...
This is the test code I just copied from the docs:
public class FavouriteProfilesControllerTest extends WithApplication {
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("play.http.router", "javaguide.tests.Routes")
.build();
}
#Test
public void testIndex() {
Result result = new FavouriteProfilesController().index(); // Inject dependencies here
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
}
}
The controller has 2 dependencies, UserProvider and MessagesApi, how do I inject/mock them into the controller test?
If you use Mockito, you can mock them like this:
#RunWith(MockitoJUnitRunner.class)
public class FavouriteProfilesControllerTest extends WithApplication {
#InjectMocks
private FavouriteProfilesController controller;
#Mock
private UserProvider userProvider;
#Mock
private MessagesApi msg;
#Test
public void test() {
Assert.assertNotNull(userProvider);
Assert.asserNotNull(msg);
}
}
The solution depends on what you intend to test. If you mean to mock the whole behavior of UserProvider and MessageApi, using Mockito may be a proper solution.
In case you want to test controller functionality with real objects, you need to inject real objects. This may be done like this:
public class FavouriteProfilesControllerTest extends WithApplication {
#Test
public void testIndex() {
running(Helpers.fakeApplication(), () -> {
RequestBuilder mockActionRequest = Helpers.fakeRequest(
controllers.routes.FavouriteProfilesController.index());
Result result = Helpers.route(mockActionRequest);
assertEquals(OK, result.status());
assertEquals("text/html", result.contentType().get());
assertEquals("utf-8", result.charset().get());
assertTrue(contentAsString(result).contains("Welcome"));
});
}
}
Using of GuiceApplicationBuilder is not necessary, if you do not mean to use different injection binding for your test. Call to Helpers.fakeApplication() invokes the default dependency injection.
You can find more about unit testing in Play here.

Spring runtime use swap bean class

#Component
#Qualifier("SUCCESS")
public class RandomServiceSuccess implements RandomService{
public String doStuff(){
return "success";
}
}
#Component
#Qualifier("ERROR")
public class RandomServiceError implements RandomService{
public String doStuff(){
throw new Exception();
}
}
the calling code
#Controller
public class RandomConroller {
#Autowired
private RandomService service;
public String do(){
service.doStuff();
}
}
What I need to do here is to have them swapped based on a value can be retrieved from some custom http header from a http request. Thank you!
I'm totally agree with Sotirios Delimanolis that you need to inject all the implementations and choose one of them at runtime.
If you have many implementations of RandomService and don't want to clutter RandomController with selection logic, then you can make RandomService implementations responsible for selection, as follows:
public interface RandomService{
public boolean supports(String headerValue);
public String doStuff();
}
#Controller
public class RandomConroller {
#Autowired List<RandomService> services;
public String do(#RequestHeader("someHeader") String headerValue){
for (RandomService service: services) {
if (service.supports(headerValue)) {
return service.doStuff();
}
}
throw new IllegalArgumentException("No suitable implementation");
}
}
If you want to define priorities for different implementations, you may use Ordered and put the injected implementations into a TreeSet with OrderComparator.
Qualifier should be used to specify which instance of the interface you want injected in the field after specifying different IDs for each one. Following #Soritios' advice you could do something like:
#Component("SUCCESS")
public class RandomServiceSuccess implements RandomService{
public String doStuff(){
return "success";
}
}
#Component("ERROR")
public class RandomServiceError implements RandomService{
public String doStuff(){
throw new Exception();
}
}
#Component
public class MyBean{
#Autowired
#Qualifier("SUCCESS")
private RandomService successService;
#Autowired
#Qualifier("ERROR")
private RandomService successService;
....
if(...)
}
...or you could obtain just the instance you want from the application context based on your parameter:
#Controller
public class RandomConroller {
#Autowired
private ApplicationContext applicationContext;
public String do(){
String myService = decideWhatSericeToInvokeBasedOnHttpParameter();
// at this point myService should be either "ERROR" or "SUCCESS"
RandomService myService = applicationContext.getBean(myService);
service.doStuff();
}
}
You can just inject both and use the one you need.
#Inject
private RandomServiceSuccess success;
#Inject
private RandomServiceError error;
...
String value = request.getHeader("some header");
if (value == null || !value.equals("expected")) {
error.doStuff();
} else {
success.doStuff();
}

Mocking a concrete class - It's always null

I'm trying to mock a concrete Class using Mockito. However, it remains null in the service under test.
My concrete class and Service:
//My Concrete Class
#Component("supporter")
public class Supporter
{
#Autowired
private IDriver driver;
public int someMethod(int){...}
...
}
//Service Class that uses this abstract class
public class Service implements IService
{
private ExceptionHandler exceptionHandler;
#Autowired
public void setExceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
private Supporter supporter;
#Autowired
public void setSupporter(Supporter supporter) {
this.supporter = supporter;
}
public int hookItem(int arg)
{
...
//supporter is always null while mock testing <----
int count = supporter.someMethod(arg);
...
return count;
}
}
My Test Code :
public class ServiceTest extends AbstractTestMockito
{
...
IService service = null;
#Mock
private ExceptionHandler exceptionHandler;
#BeforeMethod
public void setup() {
service = new Service();
}
#Test(enabled=true)
public void shouldDoSomething()
{
Supporter supporter = Mockito.mock(Supporter.class);
given(supporter.someMethod(1)).willReturn(new Integer(10));
final int response = service.hookItem(1);
//Assert...
}
}
What could be the reason for it being null?
(My classes/service are Spring beans)
Looking at the test class, it seems like you you are not injecting the mocked Supporter instance into the service instance, e.g. try to add service.setSupporter(supporter); before calling service.hookItem(1).

Categories

Resources