How to mock "System.getenv("...")" in JUnit.
Currently I am doing:
#RunWith(Parameterized.class)
#PowerMockRunnerDelegate(PowerMockRunner.class)
#PrepareForTest(System.class)
public class TestClass extends BaseTest {
public TestClass(String testCase) {
this.testCase = testCase;
}
#Before
#Override
public final void initTable() throws Throwable {
super.initTable();
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("ENV_VAR1")).thenReturn("1234");
}
...
}
I am using both PowerMock and Parameterizedrunner.
I am getting below exception for line:
PowerMockito.when(System.getenv("ENV_VAR1")).thenReturn("1234");
Exception:
org.mockito.exceptions.base.MockitoException:
'afterPropertiesSet' is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
***
Use the #RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
Use the #PrepareForTest({ClassThatCallsTheSystemClass.class}) annotation at the class-level of the test case.
Example with using EasyMock
public class SystemClassUser {
public String performEncode() throws UnsupportedEncodingException {
return URLEncoder.encode("string", "enc");
}
}
And test
#RunWith(PowerMockRunner.class)
#PrepareForTest( { SystemClassUser.class })
public class SystemClassUserTest {
#Test
public void assertThatMockingOfNonFinalSystemClassesWorks() throws Exception {
mockStatic(URLEncoder.class);
expect(URLEncoder.encode("string", "enc")).andReturn("something");
replayAll();
assertEquals("something", new SystemClassUser().performEncode());
verifyAll();
}
}
From:
https://github.com/powermock/powermock/wiki/MockSystem
So, you should add a class that uses the System.getenv, not the System class to #PrepareForTest.
This post explains why it should be done in such way.
Also, I'd like to recommend to use the System Rules library for your case. It has a good way to stub environment variables. PowerMock modifies a class byte code, so it makes test slowly. And even if it not modify a class it at least read class from disk.
Related
Now I have some other library beans that implement initializingBeans and add some time-consuming methods, but I don't want to actually execute them, I need the Spring environment, but this bean I can mock it to reduce the overall test time, what should I do
This is the pseudo code of the bean of Mock:
public final class TimeoutBean implements InitializingBean, ApplicationContextAware, ApplicationListener {
#Override
public void afterPropertiesSet() throws Exception {
initProc();
}
/**
* init
*/
public void initProc() {
//... Something time-consuming and irrelevant to this test
}
}
And my mock unit test code:
#SpringBootTest(classes = Application.class)
#DelegateTo(SpringJUnit4ClassRunner.class)
public class MockTest {
#MockBean
private TimeoutBean timeoutBean;
#Resource
private MyRepository myRepository;
#SneakyThrows
#Test
public void test() {
doNothing().when(timeoutBean).initProc();
myRepository.getById(1L);
}
}
In this way, the Mock initProc method is invalid. I can probably understand because #MockBean calls after InitializingBean#afterPropertiesSet. When the afterPropertiesSet is executed, TimeoutBean is not an Mock object, but I don't know how to solve it.
Your class TimeoutBean is final and mockito cannot mock final classes. So first you will have to fix that. After that I think it should work. For mocked classes you don't have to tell mockito to doNothing() becease that is the default behaviour for mocks.
I don't understand what you mean with: the Mock initProc method is invalid?
#Component
public class RefValidator implements Component {
#Autowired
private Repository repository;
public void validate(Context context) {
Txn txn = context.getTxn();
if (Objects.nonNull(txn) && !StringUtils.isEmpty(txn.getReferenceNumber())){
if(txn.getId() == 0){
boolean isRealmIdAndReferenceNumberExists = repository.isRefNumberExistsInSale(txn.getRealmId(), txn.getReferenceNumber());
if(isRealmIdAndReferenceNumberExists){
throw new Exception();
}
}
}
}
}
I have a class as above and want to test it using mockito. I am doing #INjectMock for RefValidator and #Mock on Repository but when I do
Mockito
.when(repository.isRefNumberExistsInSale(Mockito.anyString(),Mockito.anyString()))
.thenReturn(true);
thenReturn doesn't return true.
It's kinda hard to define what's the problem because you haven't provided your test class. But it looks like your annotations are not being processed while running a test suit.
Try one of the following:
Add #RunWith(MockitoJUnitRunner.class) above your test class
Add MockitoAnnotations.initMocks(this); inside setup method (which is annotated with #Before)
See the 2nd section of this article for help.
I've been trying to setup some unit tests to verify the logic in a ForeachWriter custom implementation but am running into a bit of mocking / duplication trouble.
I'd like to Mock an injected dependency in the ForeachWriter, but my mocks seem to be duplicated during execution. Originally I thought the mocked dependencies weren't getting called, but during debug inspection I've found that multiple versions of them seem to exist (based on hashCode).
Here's some quick sample code of what I've been trying to do:
//Class I'd like to test
public class TestForeachSink extends ForeachWriter<String> {
#Inject
SomeDependency dep;
public TestForeachSink(SomeDependency dep) {
this.dep = dep;
}
#Override
public boolean open(long partitionId, long version) {
dep.doSomethingStartupRelatedOrThrow();
return true;
}
#Override
public void process(String value) {
dep.processSomething(value);
}
#Override
public void close(Throwable errorOrNull) {
dep.closeConnections();
}
}
//Testing Class
public class TestForeachSinkTests {
#Mock SomeDependency _dep;
TestForeachSink target;
#BeforeEach
public void init() {
_dep = mock(SomeDependency.class, withSettings().serializable());
target = new TestForeachSink(_dep);
}
#Test
pubic void shouldVerifyDependencyInteractions() {
//setup stream, add data to it
stream.toDS().writeStream().foreach(target).start().processAllAvailable();
//VERIFY INTERACTIONS WITH MOCK HERE
}
}
The added data runs through the stream as expected but it seems like the mock I've passed in of SomeDependency is replaced during execution with a copy. I think that makes sense if the execution is running as though it were performing on a separate worker, but I'd still like to be able to test the ForeachWriter.
Is anyone else testing this part of the code? I haven't come across any other tests for ForeachSink custom implementations but direction on moving forward would be very appreciated!
How to bind mock of final class in Jukito ?
For example :
public final class SomeFinalClass(){
public SomeFinalClass(String someString){
}
}
//Testing class
#Runwith(JukitoRunner.class)
public class TestingClass(){
#Inject
private SomeFinalClass someFinalClassMock;
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
// bind(SomeClient.class).in(TestSingleton.class);
}
#Provides
public SomeFinalClass getSomkeFinalClass() {
return Mokito.mock(SomeFinalClass.class); //throws error
}
}
}
Is there a way i can use PowerMockito with JukitoRunner ?
You can mock a final class if you're using Mockito 2. From Mockito 2 Wiki:
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line: mock-maker-inline.
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
I am testing a legacy code that use inheritance method. I am trying to mock super-method
to verity if the super-method is being call or not.
#RunWith(PowerMockRunner.class)
public class HumanTest {
#Test
public void test() throws NoSuchMethodException, SecurityException {
// 1. arrange
Human sut = PowerMockito.spy(new Human());
PowerMockito.doNothing().when((SuperHuman) sut).run(); // SuperHuman is the parent class
// 2. action
sut.run();
// 3. assert / verify
}
}
public class Human extends SuperHuman {
#Override
public void run() {
System.out.println("human run");
super.run();
}
}
public class SuperHuman {
public void run() {
System.out.println("superhuman run");
}
}
I was expecting that "human run" will be printed. But the actual result was none printed.
PowerMockito.doNothing().when((SuperHuman) sut).run(); // SuperHuman is the parent class
This won't work in your case since PowerMockito will mock method of Human even if you made cast.
I checked your code example and could say that it is possible to suppress invocation of super class method with:
Method toReplace = PowerMockito.method(SuperHuman.class, "run");
PowerMockito.suppress(toReplace);
But it seems that method replacment feature does not work for methods of super class:
createPartialMock should support mocking overridden methods in super classes.
So this does not work:
PowerMockito.replace(toReplace).with(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Method of superclass has been invoked !");
return null;
}
});
But still you should be able to verify invocation of super method let's say indirectly, by mocking other classes which are invoked in super method only.
For instance check that System.out.println was invoked with "superhuman run" or something like this.