how to test static function of another classs in dropwizard - java

I have an issue in writing a unit test for a function which has static method of another class.
public class ClassA{
private static LoadingCache<String, String> someMap;
public static void init() {
if (someMap == null) {
someMap = CacheBuilder.newBuilder()
.concurrencyLevel(10)
.maximumSize(10) // Maximum of 10 records can be cached
.build(new CacheLoader<String, String>() {
#Override
public String load(String key) {
return "myName";
}
});
}
}
public static String getName() {
try {
return someMap.get("key");
} catch (ExecutionException ex) {
LOGGER.error("Error {}", ex.getMessage());
}
return null;
}
Trying to test the following class and it's method:
public class ClassB{
public String method(){
final String name = ClassA.getName();
return "Hello: " + name;
}
}
I am calling ClassA.init() at the start of the service in dropwizard framework. So, I think someMap gets initialized that way and all resources can directly use ClassA.getName().
But, when I try to test this, I am getting NPE because someMap is not initialized.
How can I simply do:
when(ClassB.getName()).thenReturn("myName");
Based on the comments:
I added the following to the POM:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
// test function looks as follows:
#Test
public void test(){
mockStatic(ClassA.class);
when(ClassA.getName()).thenReturn("myName");
// do the rest
}
It works!

Related

How to put the vertx #Rule about RunTestOnContext in the vertx-junit5 way?

I would like to know if it is possible migrate this kind of rule(junit) to vertx-junit5 way.
The original example is the RunOnContextTest.java from the public vertx-example repository in github.
Here is the code:
#RunWith(VertxUnitRunner.class)
public class RunOnContextTest {
/*
* This rule wraps the junit calls in a Vert.x context, the Vert.x instance can be created by the
* rule or provided like in this case.
*/
#Rule
public final RunTestOnContext rule = new RunTestOnContext(Vertx::vertx);
private Thread thread;
#Before
public void before(TestContext context) {
context.assertTrue(Context.isOnEventLoopThread());
thread = Thread.currentThread();
}
#Test
public void theTest(TestContext context) {
context.assertTrue(Context.isOnEventLoopThread());
context.assertEquals(thread, Thread.currentThread());
}
#After
public void after(TestContext context) {
context.assertTrue(Context.isOnEventLoopThread());
context.assertEquals(thread, Thread.currentThread());
}
And the highlighted dependencies are:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
Vert.x has added support for this recently.
With Vert.x 4.2.0 you can use:
#RegisterExtension
public final RunTestOnContext rt = new RunTestOnContext();
reference in github -> https://github.com/vert-x3/vertx-junit5/issues/100

ManagedExecutorService not found

I have a problem with Arquillian and ManagedExecutorServices. Arquillian is not able to find the default ManagedExecutorService. The Exception is:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:comp/DefaultManagedExecutorService
I am using IntelliJ and execute the test with GlassFish Embedded 3.1 with Arquillian 1.4.0.Final.
Here is my Unit Test:
#Slf4j
#RunWith(Arquillian.class)
public class WorkhorseTest {
#Inject
private Workhorse workhorse;
#Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addClass(Workhorse.class)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void testExecution() throws Exception {
final Future<Integer> result = workhorse.execute();
result.get(1, TimeUnit.MINUTES);
log.info("Executed...");
}
}
Here is the EJB:
#Slf4j
#Singleton
public class Workhorse {
#Resource
private ManagedExecutorService mes;
public Future<Integer> execute() {
return mes.submit(() -> {
log.info("Hello from a Runnable");
return 5;
});
}
}
How can I test ManagedExecutorServices with Arquillian?
I solved it with switching a dependency in pom.xml:
Old:
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-web</artifactId>
<version>5.0</version>
<scope>provided</scope>
</dependency>
New:
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>5.0</version>
<scope>provided</scope>
</dependency>

Feign Hystrix fallback not working

I have the below FeignClient:
#FeignClient(name="FooMS",fallback=CustomerFeign.CustomerFeignImpl.class)
public interface CustomerFeign {
#RequestMapping(value="/bar/{phoneNo}")
List<Long> getFriends(#PathVariable("phoneNo") Long phoneNo);
class CustomerFeignImpl implements CustomerFeign{
#Override
public List<Long> getFriends(Long phoneNo) {
return new ArrayList<Long>(108);
}
}
}
When the FooMS instance is down, I get a 500 error instead of the fallback being executed. Why is this happening?
adding #Component and feign.hystrix.enabled=true works fine
Tag your CustomerFeignImpl as a #Component or create a #Bean out of it.
This works for me with 2020.0.3:
In application.properties
feign.circuitbreaker.enabled=true
In pom.xml
<spring-cloud.version>2020.0.3</spring-cloud.version>
and
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
Thank you, rostlvan!
I am outlining my implementation below:
I am using Spring Cloud version 2020.0.4 and the following configuration worked for me:
in pom.xml, I have these dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
Though I'm not sure if we need to have both openfeign and hystrix dependencies. Someone can validate that!
In my application.properties I have feign.circuitbreaker.enabled=true
In my Main Application class, I have
#SpringBootApplication
#EnableFeignClients
public class MySpringBootApplication{
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}
And finally, my Feign Client, fallback and fallback factory:
UserServiceFeignClient.java
#FeignClient(name = "USER-SERVICE", fallbackFactory = UserServiceFallbackFactory.class)
public interface UserServiceFeignClient {
#GetMapping("/api/users/{userId}")
public ResponseEntity<User> getUser(#PathVariable String userId);
}
UserServiceFeignClientFallback.java
public class UserServiceFeignClientFallback implements UserServiceFeignClient{
#Override
public ResponseEntity<User> getUser(String userId) {
return ResponseEntity.ok().body(new User());
}
}
And, UserServiceFeignClientFallbackFactory.java:
#Component
public class UserServiceFallbackFactory implements FallbackFactory<UserServiceFeignClientFallback>{
#Override
public UserServiceFeignClientFallback create(Throwable cause) {
return new UserServiceFeignClientFallback();
}
}
Was facing the problem myself, until I stumbled upon the answer from #rostlvan

How to handle custom objects for #AfterReturning Aspect for Spring Boot Application

So, I have the next class:
public class MyCustomClass {
private String someField;
public String getSomeField() {
return someField;
}
public void setSomeField(String someField) {
this.someField = someField;
}
}
I would like to handle methods that return an instance of this class:
#Aspect
public class CustomAspect {
#AfterReturning(
pointcut = "execution(* com.*.*(..))",
returning = "val")
public void handleCustom(JoinPoint joinPoint, MyCustomClass val) {
System.out.println(val.getSomeField());
}
}
But it's working only if the type of val is Object:
public void handleCustom(JoinPoint joinPoint, Object val) {//...}
I tried to make something like this:
if (val instanceof MyCustomClass) {
System.out.println(((MyCustomClass) val).getSomeField());
}
But it doesn't work, in debug mode I saw that the type is ArrayList and it's empty.
I know, I'm a beginner in AOP, but Could you please advise some workarounds that could help me?
updated:
Maven dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
AspectConfig (imported to the Application class):
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages="com.aspect")
public class AspectConfig {
#Bean
public CustomAspect customAspect () {
return new CustomAspect ();
}
}
I tried to use CustomAspect as a #Component as well.
The custom object is just a DTO that is taken from maven artifact and is obtained via rest request.
So, I DO NOT have problems if the type of val is Object, everything works fine. But I do want to have MyCustomClass there instead of Object. Is it possible?
update 2:
#RestController
#RequestMapping(value = "/api/v1", produces = MediaType.APPLICATION_JSON_VALUE)
public class MyController{
#Autowired
private MyService myService;
#RequestMapping(value = "dosmth")
public ResponseEntity<?> doSmth() {
SomeObject res = myService.doSmthAndGet();
return new ResponseEntity<>(res, HttpStatus.OK);
}
}
#Service
public class MyService{
public SomeObject doSmthAndGet() {
return SomeObject.of(getMyCustomClass());
}
private MyCustomClass getMyCustomClass() {
MyCustomClass result = new MyCustomClass();
result.setSomeField("Hello, Stack!");
return result;
}
}
It seems that #AfterReturning doesn't work for my submethod:
private MyCustomClass getMyCustomClass()
It's only triggered by the method that was called from Controller:
public SomeObject doSmthAndGet()
I tried to use different executions for #AfterReturning...
What am I doing wrong?

How to make Jersey to use SLF4J instead of JUL?

I've found a useful article that explains how to make Jersey to use SLF4J instead of JUL. Now my unit test looks like (and it works perfectly):
public class FooTest extends JerseyTest {
#BeforeClass
public static void initLogger() {
java.util.logging.Logger rootLogger =
java.util.logging.LogManager.getLogManager().getLogger("");
java.util.logging.Handler[] handlers = rootLogger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
rootLogger.removeHandler(handlers[i]);
}
org.slf4j.bridge.SLF4JBridgeHandler.install();
}
public FooTest() {
super("com.XXX");
}
#Test
public void testSomething() throws Exception {
// ...
}
}
My pom.xml includes these dependencies:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
It works perfectly, but I don't want to make the same configuration in every unit test. It's an obvious code duplication, which I would like to avoid. How can I do this more effectively?
ps. Maybe it's not possible to optimize the code above and I'm doing the best I can?
If you are using the client API you can manually redirect the logs to slf4j (note that it may break in future versions although it seems unlikely):
Logger LOG = LoggerFactory.getLogger(MyClass.class); //slf4j logger
WebTarget ws = ClientBuilder.newClient(config)
.register(new LoggingFilter(new JulFacade(), true));
private static class JulFacade extends java.util.logging.Logger {
JulFacade() { super("Jersey", null); }
#Override public void info(String msg) { LOG.info(msg); }
}
The best way to do it is through a custom Listener. Being initialized before JSF servlet it should configure jul-to-slf4j bridge in contextInitialized(ServletContextEvent).
This worked for me:
public abstract class JerseyTestSFL4J extends JerseyTest {
static {
// Get JerseyTest to use SLF4J instead of JUL
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
and then having my tests extend JerseyTestSFL4J.
What it sounds like is you'd want the JUL/SLF4J configuration handle before JUnit starts testing so it could be covered for all tests? Here's a way you could do that.
Output
MySuite.init()
MySuite()
getSuiteTests()
MyTest.init()
MyTest()
test()
Code
#RunWith(AbstractTestSuite.TestSuiteRunner.class)
public abstract class AbstractTestSuite {
public static class TestSuiteRunner extends Suite {
public TestSuiteRunner(Class<?> klass) throws Exception {
super(klass, ((Class<? extends AbstractTestSuite>) klass).newInstance().getSuiteClasses());
}
}
public Class<?>[] getSuiteClasses() {
List<Class<?>> all = new ArrayList<Class<?>>();
for (Class<?> testClass : getSuiteTests()) {
all.add(testClass);
}
return all.toArray(new Class<?>[0]);
}
protected abstract Iterable<Class<?>> getSuiteTests();
}
public class MySuite extends AbstractTestSuite {
public static class MyTest {
static {
System.out.println("MyTest.init()");
}
public MyTest() {
System.out.println("MyTest()");
}
#Test
public void test() {
System.out.println("test()");
assertTrue(true);
}
}
static {
System.out.println("MySuite.init()");
}
public MySuite() {
System.out.println("MySuite()");
}
#Override
protected Iterable<Class<?>> getSuiteTests() {
System.out.println("getSuiteTests()");
return Arrays.asList(new Class<?>[] {MyTest.class});
}
}
In my app Jersey logging (with proper pom.xml and logback.xml) works fine only with
SLF4JBridgeHandler.install();
For tests you can make base abstract test with common configuration and extends other JUnit from it:
public abstract class AbstractTest {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class);
static {
SLF4JBridgeHandler.install();
}
#Rule
public ExpectedException thrown = ExpectedException.none();
#Rule
// http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev
public Stopwatch stopwatch = new Stopwatch() {
#Override
protected void finished(long nanos, Description description) {
...
Slf4jLogger from org.apache.cxf:cxf-core package is another option. It implements java.util.logging.Logger and delegate cals to slf4J.
Jersey server:
ResourceConfig config = new ResourceConfig(HelloWorldResource.class);
config.register(
new Slf4jLogger(this.getClass().getName(), null));
Jersey client:
ClientBuilder
.newClient()
.register(
new LoggingFeature(
new Slf4jLogger(this.getClass().getName(), null)));

Categories

Resources