I am trying to mockStatic method using PowerMockito , where I tried some options to mockStatic for a class, resulting in different exceptions.
#RunWith(PowerMockRunner.class)
#PrepareForTest({Base64.class})
public class BqClientFactoryTest {
#Test
public void testGetBigQueryClient() throws Exception {
mockStatic(Base64.class);
Base64.Decoder mockDecoder = mock(Base64.Decoder.class);
when(Base64.getDecoder()).thenReturn(mockDecoder);
This resulted in org.mockito.exceptions.misusing.MissingMethodInvocationException:
I used another example like this
#RunWith(PowerMockRunner.class)
#PrepareForTest({Base64.class})
public class BqClientFactoryTest {
#Test
public void testGetBigQueryClient() throws Exception {
mockStatic(Base64.class);
Base64.Decoder mockDecoder = mock(Base64.Decoder.class);
doReturn(mockDecoder).when(Base64.class, "getDecoder");
which gives me
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
If I use
BDDMockito.given(Base64.getDecoder()).willReturn(mockDecoder);
from Mocking static methods with Mockito , it still returns org.mockito.exceptions.misusing.MissingMethodInvocationException
I tried to check similar questions on SO, they haven't seemed to help.
Any help resolving this is appreciated.
I solved it following this, all other solutions didn't work for me. It is difficult to search for this solution, since there are too many on SO on the same.
PowerMockito mock single static method and return object inside another static method , PowerMock, mock a static method, THEN call real methods on all other statics
#RunWith(PowerMockRunner.class)
#PrepareForTest({Base64.class})
public class BqClientFactoryTest {
#Test
public void testGetBigQueryClient() throws Exception {
Base64.Decoder mockDecoder = mock(Base64.Decoder.class);
stub(method(Base64.class, "getDecoder")).toReturn(mockDecoder);
Related
I've a java binding for android which somewhat works bar the new feature I'm trying to integrate with. Only now I have realised that the intended callback is not happening. Here are the classes (decompiled to java) in question:
At the top level we have
public interface MyPackage {
MyPackage.Companion Companion = MyPackage.Companion.$$INSTANCE;
public static final class Companion {
#Nullable
private static MyEventHandler myEventHandler;
// $FF: synthetic field
static final MyPackage.Companion $$INSTANCE;
#Nullable
public final MyEventHandler getMyEventHandler() {
return myEventHandler;
}
public final void setMyEventHandler(#Nullable MyEventHandler var1) {
myEventHandler = var1;
}
private Companion() {
}
static {
MyPackage.Companion var0 = new MyPackage.Companion();
$$INSTANCE = var0;
}
}
}
MyEventHandler class:
public abstract class MyEventHandler {
public abstract void handleEvent(#NotNull String var1, #NotNull Properties var2);
}
Properties class:
import java.util.Map;
public class Properties extends r {
public Properties() {
}
Properties(Map<String, Object> var1) {
super(var1);
}
public Properties a(String var1, Object var2) {
super.b(var1, var2);
return this;
}
}
and the problematic r class:
public class r implements Map<String, Object> {
private final Map<String, Object> a;
various implementations...
}
So I noticed the issue when I couldnt override the HandleEvent method at the integration level and started looking at the Binding logs and found:
Warning=>
BINDINGSGENERATOR: Warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler. (BG8801)
And in build logs:
message BG0000: warning BG8102: Class MyPackage....Properties has unknown base type MyPackage....r.
warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler.
As it was obvious r is an obfuscated class I need to make chagnes to my Metadata so I went ahead and popped in:
<attr path="/api/package[#name='MyPackage']/class[#name='r']" name="obfuscated">false</attr>
Which resulted in the R being generated but now I get the 5 following compile error:
Error CS0535: 'R' does not implement interface member 'IMap.EntrySet()' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.KeySet()'. 'R.KeySet()' cannot implement 'IMap.KeySet()' because it does not have the matching return type of 'ICollection'. (CS0738)
Error CS0535: 'R' does not implement interface member 'IMap.Put(Object?, Object?)' (CS0535)
Error CS0535: 'R' does not implement interface member 'IMap.PutAll(IDictionary?)' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.Values()'. 'R.Values()' cannot implement 'IMap.Values()' because it does not have the matching return type of 'ICollection'. (CS0738)
I tried to make a managed return using
<attr path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet' and count(parameter)=0]" name="managedReturn">Java.Util.IMap</attr>
With same number of compile error as above. Then I tried removing the node using:
<remove-node path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet']"/>
Still no luck. :(
What am I missing here? Any pointers/suggestions will be appreciated!
It seems like you are trying to expose a Map to C# and as you stated, Java Generics are not handled very well.
In a very popular social network you received an answer from #mattleibow. I do not take credit for his answer but I went to check nonetheless and it seems fine.
If you look at the description of the Java.Lang.HashMap type
https://learn.microsoft.com/en-us/dotnet/api/java.util.hashmap?view=xamarin-android-sdk-9 it's a good candidate for you to expose.
You can also try with the corresponding interface for better safety https://learn.microsoft.com/en-us/dotnet/api/java.util.imap?view=xamarin-android-sdk-9
If it works you will still have to cast the types yourself.
Please answer to the comment to say that problem is solved for the sake of future generations arriving on this post :D
Credit is not mine so don't give it to me :-)
John,
I got arround fixing it by providing implementation of the the said methods in a partial class. Basically added a new file called R.cs under Additions folder as follows:
namespace YourNameSpace
{
public partial class R
{
public void PutAll(System.Collections.IDictionary p0)
{
PutAll(p0);
}
public Java.Lang.Object Put(Java.Lang.Object key, Java.Lang.Object value)
{
return Put(key, value);
}
public System.Collections.ICollection EntrySet()
{
return EntrySet();
}
public System.Collections.ICollection KeySet()
{
return KeySet();
}
public System.Collections.ICollection Values()
{
return Values();
}
}
}
I couldn't get it to work by adding XML transformation, but I think there was some tooling issue.
I have to write a Mockito+Junit test for a method and that method reads the data from a properties file. When I am trying to execute my test case the properties file is loading but it is returning null. Following is my code:
#RestController
#PropertySource("classpath:/com/example/prop.properties")
public class ReadProp {
#Value("${name}")
private String name;
#Value("${rollNo}")
private String rollNo;
#RequestMapping(value="/")
public void getDetails(){
System.out.println(name);
System.out.println(rollNo);
}
}
The test case is as follows
#RunWith(MockitoJUnitRunner.class)
#PropertySource("classpath:/com/example/prop.properties")
public class ReadPropTest {
#Mock
private ReadProp readProp;
#Value("${name}")
private String name;
#Value("${rollNo}")
private String rollNo;
#Test
public void readValues() {
System.out.println(name);
System.out.println(rollNo);
readProp.getDetails();
}
}
Let's start at the beginning... Your test has many problems, the first being that you don't actually have anything to test...
#Mock
private ReadProp readProp;
This, together with #RunWith(MockitoJUnitRunner.class) makes your readProp object a mock object. A mock object contains no logic. It has nothing to do with your original ReadProp class except the method names, etc. But the method themselves don't actually DO anything (unless you tell them to).
So, first problem: You are not test YOUR RealProp class, but a mock object, which doesn't help. You are creating something that only looks like a RealProp object and then you test that, but of course, that doesn't tell you anything. Mocks are there to help you simplify dependencies, etc. in your test - but it makes no sense to actually test the mock.
So, don't. Instead, make a real RealProp.
Another problem is, that System.out is not very good to test, but I assume that's just temporary code, so let's ignore that for a moment...
The next question is, what do you want to test. There are two possibilities:
a) You want to test that, under the assumption that the fields name and rollNo were filled correctly by whatever dependency injection framework (spring, in this case) you are using, the method getDetails will use them correctly.
b) You want to test that the injection of the values works and also the method getDetails uses that values.
These are two different tests. a) would be a true unit test, since it's limited to this "unit". b) would be more complex, since it doesn't just look at this unit, but also at the Spring environment around it. I would not go so far to call it an integration test, but it's more than a simple unit test.
Personally, I try to avoid the Spring environment in my unit tests as far as possible and concentrate on my own code, testing the Spring integration later in real integration tests, but that's as much personal preference as anything else.
Let's start with a)...
public class ReadPropTest {
private ReadProp readProp = new ReadProp();
#Before
public void init() {
Whitebox.setInternalState(readProp, "name", "someName");
Whitebox.setInternalState(readProp, "rollNo", "someRollNo");
}
#Test
public void myTest() {
...
}
}
Of course, you can also use Spring's ReflectionTestUtils instead of Mockito's Whitebox, doesn't matter.
And for b), you could try something like this. Of course you migth have to play around with the Configuration a bit, as it depends on your setup.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {"classpath:applicationContext-spring.xml" })
public class ReadPropTest {
#Autowired
private ReadProp readProp;
...
}
Lambda translation is a two step process, One: desugaring the lambda into a static method in same class.
public class Main {
public static void main(String[] args) {
Runnable r = () -> System.out.println("Hello");
System.out.println(Arrays.asList(Main.class.getDeclaredMethods()));
}
}
[private static void Main.lambda$main$0(), public static void
Main.main(java.lang.String[])]
Two: generation of a class that implements the Functional Interface.
System.out.println("A class has been generated: " + r.getClass());
System.out.println("That implements a Functional Interface: " + Arrays.asList(r.getClass().getInterfaces()));
A class has been generated: class Main$$Lambda$1/149928006
That implements a Functional Interface: [interface java.lang.Runnable]
Question: What is the need of this static method? Why can't the lambda body be put directly into the interface method? Something like:
class Main$$Lambda$1 {
public void run() {
/* Lambda body here */
}
}
In addition to the correct answers given here (because the current scheme is more efficient, reducing capture/linkage costs for lambdas and reducing code duplication), there are a few other reasons why your idea simply doesn't make sense.
Where would the bytecode come from in the first place? The lambda proxy class is generated at runtime, not compile time. If we were to stuff the bytecode into the proxy class, it would have to come from somewhere. That would mean we'd have to put it into the capturing class file and then copy it into the proxy class. Here, it just lives in the capturing class and we're done.
Access control. What if the lambda body calls a private method? By desugaring it into the capturing class, it automatically acquires the access control context of the capturing class (which it is logically a part of.) If we put the bytecode in the proxy class, we'd have to do additional magic to give it the right access control context.
Because this way it's actually cheaper. Generating a lambda from the method on the fly during the first invocation is better than loading a separate class via class loader. Internally it uses UNSAFE.defineAnonymousClass which is more light-weight class than normal. Such "lambda-class" is not bound to any class loader, so can be easily garbage-collected when it's no longer necessary. Also I guess there are plans to make this mechanism even more light-weight and faster. For normal anonymous class this would not be possible as from the point of JVM such classes don't differ from usual classes and much more heavy.
Your test is incomplete.
public class Lambda {
private String hello = "Hello from instance";
public static void main(String[] args) {
Runnable r = () -> System.out.println("Hello");
for (Method m: Lambda.class.getDeclaredMethods()) {
System.out.println(m);
}
}
public void instanceMethodWithAccessToInstanceVariables(){
Runnable r = () -> System.out.println(hello);
}
public void instanceMethodWithoutAccessToInstanceVariables(){
Runnable r = () -> System.out.println("Hello from instance");
}
}
This results in the following:
public void Lambda.instanceMethodWithAccessToInstanceVariables()
public void Lambda.instanceMethodWithoutAccessToInstanceVariables()
private static void Lambda.lambda$instanceMethodWithoutAccessToInstanceVariables$2()
private void Lambda.lambda$instanceMethodWithAccessToInstanceVariables$1()
private static void Lambda.lambda$main$0()
public static void Lambda.main(java.lang.String[])
This clearly shows several cases:
lambdas in static method declare static method
lambdas in instance methods using instance variables declare instance methods
lambdas in instance methods not using instance variables declare static method
The two first are rather logical. Why would you expect a static member to access an instance member? Same for the instance method.
The real question is why does an instance method not using any instance variables declare a static method?
Well, this is also for performance and safety reasons mentioned by Tagir.
I was trying to verify whether my log warning message is written via NUnit mocking. I am getting this error message :
An exception of type 'System.NotSupportedException' occurred in Moq.dll but was not handled in user code
Additional information: Invalid verify on a non-virtual (overridable in VB) member: m => m.LogWarning(String.Format("comments not found for part number :{0}", (Object)0), new[] { "111" })
code:
mockLogger.Verify(m => m.LogWarning($"comments not found for part number :{0}", "111"), Times.Exactly(1));
This is happening because NUnit mocking framework does not support extension methods. A few people on stack overflow have suggested to use Log method instead of level wise methods.
What am I missing?
Firstly, you don't need the $ at the start of the string. That's for string interpolation. The LogWarning message is doing a string.format, hence the {0}
Mock frameworks cannot directly mock static methods. The problem in your case is the LogWarning method - that is the static (extension) method.
The simplest way of overcoming this issue is by using a wrapper class. Here's how I got it, in your case.
Firstly I created an interface
public interface IMyLogWarning
{
void LogWarning(string msg, params object[] args);
}
Then I created a class which implements that interface
public class MyLogWarning<T> : IMyLogWarning where T : class
{
private readonly ILogger _logger;
public MyLogWarning(ILogger<T> logger)
{
// Using constructor for DI
_logger = logger;
}
public void LogWarning(string msg, params object[] args)
{
_logger.LogWarning(msg, args);
}
}
The reason for these two is that I'll use these in my code as well as the unit test.
The constructor in the class is setup so it can be populated using dependency injection, something like this in your ConfigureServices method. Feel free to change this; was a quick stab at it on my part.
services.AddTransient<IMyLogWarning, MyLogWarning<MyViewModel>>();
You can then create a unit test that's roughly like this
[Test]
public void LoggingTest_LogAMessage_ConfirmedLogWasRun()
{
// TODO - add the rest of your test code
// Arrange
var warningMsg = "comments not found for part number :{0}";
var partNumber = "111";
var mockLogger = new Mock<IMyLogWarning>();
// Act
mockLogger.Object.LogWarning(warningMsg, partNumber);
// Assert
mockLogger.Verify(m => m.LogWarning(warningMsg, partNumber), Times.Exactly(1));
}
I'd like to display a warning message on specific pages 5 minutes prior to a system shutdown. Rather than add it manually to each these pages I created a #ControllerAdvice class with a #ModelAttribute method that adds the message to the Model parameter, but from what I understand reading the documentation and SO and some initial testing this model attribute will be added to every method with a #RequestMapping.
I realize I could refactor my code so that the targeted methods are all in one controller and limit the #ControllerAdvice to that one controller, but I would end up with a collection of otherwise non-related methods in that controller which muddies up the overall structure of my controllers.
So, is there a way to indicate which specific methods in multiple controllers the #ModelAttribute is applied to? Would a custom annotation be a solution (not sure how that would work)? I'd like to do this via annotations if possible.
Edit:
The #ControllerAdvice code is pretty basic:
#ControllerAdvice
public class GlobalModelController {
private final Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
private MaintenanceInterceptor maintInterceptor;
#ModelAttribute()
public void globalAttributes(Model model, Locale locale) {
if (maintInterceptor.isMaintenanceWindowSet() && !maintInterceptor.isMaintenanceInEffect()) {
String msg = maintInterceptor.getImminentMaint(locale);
model.addAttribute("warningMaint", msg);
logger.debug("maint msg= " + msg);
}
}
}
A controller advice can be limited to certain controllers (not methods) by using one of the values of the #ControllerAdvice annotation, e.g.
#ControllerAdvice(assignableTypes = {MyController1.class, MyController2.class})
If you need to do it on a method level I suggest to take a look at Interceptors.
Thanks to #zeroflagL for pointing me to the interceptor solution. I ditched the #ControllerAdvice approach and ended up with this:
Custom annotation:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface MaintAware {
String name() default "MaintAware";
}
Interceptor:
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod)handler;
Method method = handlerMethod.getMethod();
MaintAware maintAware = method.getAnnotation(MaintAware.class);
if (maintAware != null) {
Locale locale = request.getLocale();
if (isMaintenanceWindowSet() && !isMaintenanceInEffect()) {
String msg = getImminentMaint(locale);
if (!msg.isEmpty())
modelAndView.addObject("warningMaint", msg);
}
}
super.postHandle(request, response, handler, modelAndView);
}
Now I can annotate the specific methods that require the maintenance notification. Easy peasy. :)