I am leaning CDI Annotation have a question with respect to Produces Annotation:
I have a Bank
public interface Bank {
public void withdrawal();
public void deposit();
}
Two Implementation flavors
public class BankOfAmerica implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Bank Of America");
}
public void deposit() {
System.out.println("You are depositing in Bank Of America");
}
}
public class Chase implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Chase");
}
public void deposit() {
System.out.println("You are depositing in Chase");
}
}
A Qualifier
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankProducer {
}
An Enum
public enum BankName {
DCU(DCU.class), Chase(Chase.class), BankOfAmerica(BankOfAmerica.class);
private Class<? extends Bank> bankType;
private BankName(Class<? extends Bank> bankType) {
this.bankType = bankType;
}
public Class<? extends Bank> getBankType() {
return bankType;
}
}
An Annotation to bind the BankName
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankType {
#Nonbinding
BankName value();
}
A Factory
public class BankFactory {
#Produces
#BankProducer
public Bank createBank(#Any Instance<Bank> instance, InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
BankType bankTypeAnnotation = annotated.getAnnotation(BankType.class);
Class<? extends Bank> bankType = bankTypeAnnotation.value().getBankType();
return instance.select(bankType).get();
}
}
And a JUnit
#RunWith(Arquillian.class)
public class ProducesTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class).addPackages(true, "com.tutorial.produces")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml").merge(getDependecies());
}
private static JavaArchive getDependecies() {
JavaArchive[] javaArchives = Maven.configureResolver().loadPomFromFile("pom.xml")
.resolve("org.projectlombok:lombok").withTransitivity().as(JavaArchive.class);
JavaArchive mergedLibraries = ShrinkWrap.create(JavaArchive.class);
for (JavaArchive javaArchive : javaArchives) {
mergedLibraries.merge(javaArchive);
}
return mergedLibraries;
}
#Test
public void create() {
assertEquals(banks.getBankOfAmerica().getClass(), BankOfAmerica.class);
}
}
POM - using tomee
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0-1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>7.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.2.2</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
I am getting a NullPointer exception in my factory createBank method. InjectionPoint is Null. What is the issue and how do I resolve it?
Alternate Solution: Tried Weld
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.8.Final</version>
</dependency>
JUnit
#RunWith(WeldJUnit4Runner.class)
public class ProducesWeldTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Test
public void create() {
assertEquals(bankOfAmerica.getClass(), BankOfAmerica.class);
}
}
WeldContext and WeldJUnit4Runner are from here -
http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se/
As I already mentioned in my comment to the post, the CDI implememtatin seems to work. I think the problem lies in the test. Originally, I just wrote a simple test with a main() method and everything works. Now I moved the same code to the JUnit test and it still works. To test your implementation I just added the following client for your factory and a test class as follows:
public class BankClient {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
public void deposit() {
bankOfAmerica.deposit();
}
public void withdrawal() {
bankOfAmerica.withdrawal();
}
}
// JUnit test
public class BankServiceTest {
private static Weld weld = new Weld();
private static BankClient sut;
#BeforeClass
public static void initWeld() {
WeldContainer container = weld.initialize();;
sut = container.instance().select(BankClient.class).get();
}
#Test
public void deposit_should_be_invoked() {
sut.deposit();
}
#Test
public void withdrawal_should_be_called() {
sut.withdrawal();
}
#AfterClass
public static void shutDown() {
weld.shutdown();
}
}
After executing the test, you should see the following output on the console and JUnit green bar:
You are depositing in Bank Of America
You are withdrawing from Bank Of America
Related
This question already has answers here:
How to verify static void method has been called with power mockito
(2 answers)
Closed 3 years ago.
I have a class A which has a static method testA(String auditUser, Timestamp timestamp) which calls a static method of class B if auditUser is admin.
I am trying to write test for class A.
How can I verify the static method of B got called or not?
class A {
public void static testA(String auditUser, Timestamp timestamp) {
if ("admin".equalsIgnoreCase(auditUser) {
B.testB(timestamp);
}
}
}
class B {
public void static testB(Timestamp timestamp) {
//...some logic...//
}
}
I add void to your static method for compile.
#SpringBootTest
#RunWith(PowerMockTestRunner.class)
#PrepareForTest(value = B.class)
public class TestClass {
#Test
public void testBAdmin() {
String auditUser = "admin";
Timestamp timestamp = new Timestamp(1577447182l);
PowerMockito.mockStatic(B.class);
//You can mock method here, if you need return value like this
//when(B.testB(timestamp)).thenReturn("some_value");
A.testA(auditUser, timestamp);
PowerMockito.verifyStatic(B.class);
B.testB(timestamp);
}
#Test
public void testBNotAdmin() {
String auditUser = "not_admin";
Timestamp timestamp = new Timestamp(1577447182l);
PowerMockito.mockStatic(B.class);
//You can mock method here, if you need return value like this
//when(B.testB(timestamp)).thenReturn("some_value");
A.testA(auditUser, timestamp);
PowerMockito.verifyZeroInteractions(B.class);
}
}
class A {
public static void testA(String auditUser, Timestamp timestamp) {
if ("admin".equalsIgnoreCase(auditUser)) {
B.testB(timestamp);
}
}
}
class B {
public static void testB(Timestamp timestamp) {
//...some logic...//
}
}
And don't forget about maven dependency
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
Please follow these steps:
Add #PrepareForTest({ClassA.class, ClassB.class})
These use PowerMockito.mockStatic(ClassA.class);, PowerMockito.mockStatic(ClassB.class);
The use PowerMockito.when(ClassA.testA(ArgumentMatchers.anyString(), ArgumentMatchers.any())).thenReturn(PowerMockito.when(ClassB.testB(ArgumentMatchers.any()))).thenReturn(any());
I have two-page objects called OrderSelection and OrderDetails. In addition, I have SharedState class and OrderSelectionStepDef and OrderDetailsStepDef. I declared two variables for OrderSelection and OrderDetails in SharedState. However, they are not initialized in the constructor of SharedState.
In OrderSelectionStepDef and OrderDetailsStepDef classes, I declared their constructors and pass SharedState object.
public OrderSelectionStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
public OrderDetailsStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
When I call sharedState.orderDetails within OrderDetailsStepDef or OrderSelectionStepDef a NullPointerException was thrown.
Then, I initialized OrderSelection and OrderDetails class objects in SharedState constructor. Then the issue was solved. But is this implementation ok with cucumber pico container concept?.
Step 1. OrderSelectionStepDef & OrderDetailsStepDef would look like below (please change name as per your implementation)
/**
* Step Definition implementation class for Cucumber Steps defined in Feature file
*/
public class HomePageSteps extends BaseSteps {
TestContext testContext;
public HomePageSteps(TestContext context) {
testContext = context;
}
#When("^User is on Brand Home Page (.+)$")
public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
homePage = new HomePage().launchBrandSite(siteName);
testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
}
#Then("^Clicking on Sign In link shall take user to Sign In Page$")
public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
signInPage = homePage.ecommSignInPageNavigation();
testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
}
For your reference
public class BaseSteps {
protected HomePage homePage;
protected PLPPage plpPage;
protected PDPPage pdpPage;
protected ShoppingBagPage shoppingBagPage;
protected ShippingPage shippingPage;
More implementation goes here.....
}
Step 2. Please add below 2 Classes under your framework -
First, Java file name - ScenarioContext.java
public class ScenarioContext {
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext = new HashMap<String, Object>();
}
public void setContext(Context key, Object value) {
scenarioContext.put(key.toString(), value);
}
public Object getContext(Context key){
return scenarioContext.get(key.toString());
}
public Boolean isContains(Context key){
return scenarioContext.containsKey(key.toString());
}
}
Second, Java file name - TestContext.java
public class TestContext {
public ScenarioContext scenarioContext;
public TestContext(){
scenarioContext = new ScenarioContext();
}
public ScenarioContext getScenarioContext() {
return scenarioContext;
}
}
Step 3. POM Dependency - picocontainer shall be as per your cucumber version
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
</dependency>
Hope this helps.
I just encounter a problem when using spring state machine #WithStateMachine.
#WithStateMachine just work when I use it on inner class which defined in the class annotated by #EnableStateMachine, but when I define class in other place it seems not work.
Here is my code:
#Configuration#EnableStateMachine public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
#Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.UNPAID)
.states(EnumSet.allOf(States.class));
}
#Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)
.event(Events.PAY)
.and()
.withExternal()
.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
.event(Events.RECEIVE);
}
#Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withConfiguration()
.autoStartup(true);
}
#WithStateMachine
public class Action {
private Logger logger = LoggerFactory.getLogger(getClass());
#OnTransition(target = "UNPAID")
public void create() {
logger.info("UNPAID");
}
#OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
public void pay() {
logger.info("WAITING_FOR_RECEIVE");
}
#OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive() {
logger.info("DONE");
}
}}
but when I define Action in another class file, it is not work
my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>1.2.3.RELEASE</version>
</dependency><dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
#WithStateMachine is a meta-annotation having spring #Component. Check that your Action class is either component scanned or created manually as #Bean.
Then it exist in application context and statemachine can find it.
I am implementing a restful service in java using JAX-RS, and when testing the service it works only for one of my methods, when I add a new method with a different #PATH annotation the test web page is just blank without errors
My resource class
#Path("beer")
public class BeerResources {
#Context
private UriInfo context;
/**
* Creates a new instance of BeerResources
*/
public BeerResources() {
}
#GET
#Path("/costliest")
#Produces(MediaType.TEXT_PLAIN)
public String getCostliest() {
//TODO return proper representation object
return new BusinessLayer().getCostliest();
}
#GET
#Path("/cheapest")
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
//TODO return proper representation object
return new BusinessLayer().getCheapest();
}
}
Application config class
#javax.ws.rs.ApplicationPath("/webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(beerrestful.BeerResources.class);
}
}
You can try to use Spring Boot + JAX-RS approach or Spring Boot + Spring MVC. Here are both of them on my Github page.
Also there is Spring Boot + JAX-RS source code:
Application.java:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
new Application().configure(builder).run(args);
}
}
DrinkEndpoint.java:
#Component
#Path("/drinks")
public class DrinkEndpoint {
#Autowired
private DrinkService drinkService;
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public Iterable<Drink> getCostliest() {
return drinkService.getDrinks();
}
#GET
#Path("/{drink}")
#Produces(MediaType.APPLICATION_JSON)
public Response getCheapest(#PathParam("drink") String name) {
Optional<Drink> drink = drinkService.getDrink(name);
if (drink.isPresent()) {
return Response.status(201).entity(drink.get().getName()).build();
} else {
return Response.status(201).entity("NOT_FOUND").build();
}
}
}
DrinkService.java:
public interface DrinkService {
Iterable<Drink> getDrinks();
Optional<Drink> getDrink(String name);
}
DrinkServiceImpl.java:
#Component
public class DrinkServiceImpl implements DrinkService {
private List<Drink> drinks = new ArrayList<Drink>() {{
add(new Drink("Coca Cola", 1886));
add(new Drink("Pepsi", 1903));
}};
public Iterable<Drink> getDrinks() {
return drinks;
}
public Optional<Drink> getDrink(String name) {
for (Drink drink : drinks) {
if (drink.getName().equalsIgnoreCase(name)) {
return Optional.of(drink);
}
}
return Optional.empty();
}
}
ApplicationConfig.java:
#Component
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(DrinkEndpoint.class);
}
}
Drink.java:
public class Drink {
private String name;
private int since;
public Drink(String name, int since) {
this.name = name;
this.since = since;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSince() {
return since;
}
public void setSince(int since) {
this.since = since;
}
}
pom.xml:
<project>
....
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
To start application run:
mvn spring-boot:run
Then open in browser:
http://localhost:8080/drinks/list
http://localhost:8080/drinks/pepsi
Make sure you are returning proper XML format
Example:
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
return "<abc>xyz</abc>";
}
If BusinessLayer().getCheapest() function is returning String and you have used tag #Produces(MediaType.APPLICATION_XML) it will just show you a blank page.
Use appropriate MediaType in #Produces tag according to the value returned from BusinessLayer().getCheapest() function
I created this test in Jersey (from the docs), which works fine, with one problem: the #WebListener ServletContextListener is not being invoked.
The Resource classes that I need to test rely on an attribute set on the ServletContext by the ServletContextListener.
Can I make sure it is invoked, or can I manipulate the ServletContext in some other way?
public class SimpleTest extends JerseyTest {
#WebListener
public static class AppContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context initialized");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed");
}
}
#Path("hello")
public static class HelloResource {
#GET
public String getHello() {
return "Hello World!";
}
}
#Override
protected Application configure() {
return new ResourceConfig(HelloResource.class);
}
#Test
public void test() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
}
I added these dependencies to make this work:
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.18</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.18</version>
</dependency>
The JerseyTest needs to be set up to run in a Servlet environment, as mentioned here. Here are the good parts:
#Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
#Override
protected DeploymentContext configureDeployment() {
ResourceConfig config = new ResourceConfig(SessionResource.class);
return ServletDeploymentContext.forServlet(new ServletContainer(config))
.addListener(AppContextListener.class)
.build();
}
See the APIs for
ServletDeploymentContext and
ServletDeployementContext.Builder (which is what is returned when you call forServlet on the ServletDeploymentContext).