How to invoke #BeforeMethod block before #PostConstruct - java

I am writing below Spring Unit test code. Unit test #Before method is not getting executed. Since it is directly running #PostConstruct i am getting erorrs Caused by: java.lang.IllegalArgumentException: rate must be positive because the default value is 0.00. I want to set some value to request max limit so that postcontstruct block will go through smoothly. what is wrong in my code? Please help.
#Component
public class SurveyPublisher {
#Autowired
private SurveyProperties surveyProperties;
#PostConstruct
public void init() {
rateLimiter = RateLimiter.create(psurveyProperties.getRequestMaxLimit());
}
}
public void publish() {
rateLimiter.acquire();
// do something
}
}
//Unit test class
public class SurveyPublisherTest extends AbstractTestNGSpringContextTests {
#Mock
SurveyProperties surveyProperties;
#BeforeMethod
public void init() {
Mockito.when(surveyProperties.getRequestMaxLimit()).thenReturn(40.00);
}
#Test
public void testPublish_noResponse() {
//do some test
}
}

Just realized it will always run postConstruct method before Junit callback methods cause spring takes the precedence. As explained in the documentation -
if a method within a test class is annotated with #PostConstruct, that
method runs before any before methods of the underlying test framework
(for example, methods annotated with JUnit Jupiter’s #BeforeEach), and
that applies for every test method in the test class.
Solution to you issue -
As #chrylis commented above refactor your SurveyPublisher to use constructor injection to inject the rate limiter. So you can then easily test.
Inject Mock/Spy bean which is causing the problem
Create test config to give you the instance of the class to use as #ContextConfiguration
#Configuration
public class YourTestConfig {
#Bean
FactoryBean getSurveyPublisher() {
return new AbstractFactoryBean() {
#Override
public Class getObjectType() {
return SurveyPublisher.class;
}
#Override
protected SurveyPublisher createInstance() {
return mock(SurveyPublisher.class);
}
};
}
}

Here is the simple one worked.
#Configuration
#EnableConfigurationProperties(SurveyProperties.class)
static class Config {
}
#ContextConfiguration(classes = {
SurveyPublisherTest.Config.class })
#TestPropertySource(properties = { "com.test.survey.request-max-limit=1.00" })
public class SurveyPublisherTest extends AbstractTestNGSpringContextTests {
//Remove this mock
//#Mock
//SurveyProperties surveyProperties;
}

Related

How to configure #MockBean before #PostConstruct?

I have a service that has a DataProvider which I want to mock.
Problem: the service uses the data provider in #PostConstruct. But when I use #MockBean, the mocked values are not jet present in #PostConstruct.
What could I do?
#Service
public class MyService {
private List<Object> data;
#Autowired
private DataProvider dataProvider;
#PostConstruct
public void initData() {
data = dataProvider.getData();
}
public void run() {
System.out.println(data); //always null in tests
}
}
#SpringBootTest
public class Test {
#MockBean
private DataProvider dataProvider;
#Test
public void test() {
when(dataProvider.getData()).thenReturn(mockedObjects);
//dataProvider.init(); //this fixes it, but feels wrong
service.run();
}
}
IMHO unit testing MyService would be a better solution for this particular scenario (and I wouldn't feel wrong about calling initService manually in that case), but if you insist...
You could simply override the DataProvider bean definition for this particular test and mock it beforehand, sth like:
#SpringBootTest(classes = {MyApplication.class, Test.TestContext.class})
public class Test {
#Test
public void test() {
service.run();
}
#Configuration
static class TestContext {
#Primary
public DataProvider dataProvider() {
var result = Mockito.mock(DataProvider.class);
when(result.getData()).thenReturn(mockedObjects);
return result;
}
}
}
You might need to set spring.main.allow-bean-definition-overriding to true for the above to work.

Mockito when isn't replacing original method behaviour

I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.

Mockito to test an autowired field

public interface Dummy {
public returnSomething doDummyWork(arg1, agr2);
}
public class A implements Dummy {
#AutoWired
PrintTaskExecutor printTaskExecutor;
public returnSomething doDummyWork(arg1, agr2) {
callingVoidMethod();
return something;
}
public void callingVoidMethod() {
printTaskExecutor.printSomething(arg1, arg2);
}
}
public class testDummy {
#Autowired
Dummy dummyA//this bean is configured in ApplicationContext.xml and it works fine.
#Mock
PrintTaskExecutor printaskExecutor;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
printaskExecutor = Mockito.mock(PrintTaskExecutor.class);
Mockito.doNothing().when(printaskExecutor).printSomething(anyString(), anyString());
}
#Test
Public void testA
{
Dummy.doDummyWork(arg1, arg2);//I m giving actual arguments
//instead of moocking it calls the original method.
Mockito.verify(printaskExecutor, times(1)).printSomething(anyString(), anyString());
}
}
I have an autowired TaskExecutor in the class I m testing and I want to mock it.I have tried this in my code and It calls the actual method instead of do nothing and in the verify it errors out saying no interactions happened. How should I handle this situation?
I try to avoid using Mockito and Bean Containers together in one test. There are solutions for that problem. If you use Spring you should use #RunWith(SpringJUnit4Runner.class). More on this subject: Injecting Mockito mocks into a Spring bean
The clean way: Actually your class testDummy does not test Dummy but A. So you can rewrite your class in following way:
public class testA {
#Mock
PrintTaskExecutor printTaskExecutor;
#InjectMocks
A dummyA;
...
BTW: #Mock together with initMocks(this) and printaskExecutor = Mockito.mock(PrintTaskExecutor.class); do the same, you can skip the latter statement.

Injection of mocks doesn't work with when clauses

I have to test the following class, with an autowired object:
public class Provider {
#Autowired
private Service service;
public Provider() {}
public Provider(final Service service) {
this.service = service;
}
// Other code here
}
I created my test as follows:
#RunWith(PowerMockRunner.class)
public class ProviderTest {
#Mock(name="service") Service service;
#Mock Score score;
#InjectMocks Provider provider = new SearchResultProvider();
#Before
public void setup() {
when(service.process()).thenReturn(score);
}
#Test
public void my_test() {
provider.execute(); // It fails, because service.process() returns null
// Other code here
}
// Other tests here
}
However, when I run the test, it fails. Everything is fine, except the clause when(...) that seems to be ignored.
That causes the test to fail on the call to provider.execute(). Inside this function the call to service.process() is executed and then I would expect a "score mock" to be returned. But a null value is returned instead.
What have I done wrong?
The sample code show no need for powermock, I suppose there's PowerMock because some code is final. But the test don't prepare the classes to be definalized.
I will suppose the code with a final method is the Service
public class Service {
public final Score process() {
throw new NullPointerException("lol");
}
}
Then the code won't pass, unless the test prepares the classes to be definalized :
#RunWith(PowerMockRunner.class)
#PrepareForTest(Service.class)
public class ProviderTest {
...
}

How do I test gwtp addToPopupSlot?

I have a gwtp presenter, in some cases it must add to popupslot another presenter.
How can I verify this fact in test?
I'm using Jukito for tests.
Presenter's code:
...
#Override
public void onAddPersonClick() {
editPersonPresenter.initForCreating();
addToPopupSlot(editPersonPresenter);
}
...
Test:
#RunWith(JukitoRunner.class)
public class PersonsPagePresenterTest {
#Inject
PersonPagePresenter personPagePresenter;
#Test
public void testAddPersonClick() {
personPagePresenter.onAddPersonClick();
//how to verify addToPopupSlot(editPersonPresenter);?
}
}
The problem is that all injected presenters in test are not mocks (only their views are mocks)
You'll need to spy the instance using mockito since you want to verify that an instance method is called. Notice that I removed the #Inject on the PersonPagePresenter field as it's injected through the setUp method
#RunWith(JukitoRunner.class)
public class PersonsPagePresenterTest {
PersonPagePresenter personPagePresenter;
#Before
public void setUp(PersonPagePresenter personPagePresenter) {
this.personPagePresenter = Mockito.spy(personPagePresenter);
}
#Test
public void testAddPersonClick() {
personPagePresenter.onAddPersonClick();
Mockito.verify(personPagePresenter).addToPopupSlot(editPersonPresenter);
}
}

Categories

Resources