Skip to content

Commit

Permalink
MockBean - make it possible to specify the bean class
Browse files Browse the repository at this point in the history
- also add convenient MockBean.Builder.selectedAlternative()
- resolves #22
  • Loading branch information
mkouba committed Jan 3, 2018
1 parent 2b9f607 commit 838c354
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ public static Weld createWeld() {
protected volatile WeldContainer container;

protected AbstractWeldInitiator(Weld weld, List<Object> instancesToInject, Set<Class<? extends Annotation>> scopesToActivate, Set<Bean<?>> beans,
Map<String, Object> resources, Function<InjectionPoint, Object> ejbFactory, Function<InjectionPoint, Object> persistenceUnitFactory, Function<InjectionPoint, Object> persistenceContextFactory) {
Map<String, Object> resources, Function<InjectionPoint, Object> ejbFactory, Function<InjectionPoint, Object> persistenceUnitFactory,
Function<InjectionPoint, Object> persistenceContextFactory) {
this.instancesToInject = new ArrayList<>();
for (Object instance : instancesToInject) {
this.instancesToInject.add(createToInject(instance));
Expand All @@ -99,6 +100,14 @@ protected AbstractWeldInitiator(Weld weld, List<Object> instancesToInject, Set<C
this.weld = weld;
if (hasScopesToActivate() || hasBeansToAdd()) {
this.extension = new WeldCDIExtension(this.scopesToActivate, this.beans);
for (Bean<?> bean : this.beans) {
if (bean instanceof MockBean) {
MockBean<?> mockBean = (MockBean<?>) bean;
if (mockBean.isAlternative() && mockBean.isSelectForSyntheticBeanArchive()) {
this.weld.addAlternative(mockBean.getBeanClass());
}
}
}
this.weld.addExtension(this.extension);
} else {
this.extension = null;
Expand Down
87 changes: 77 additions & 10 deletions junit-common/src/main/java/org/jboss/weld/junit/MockBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import javax.enterprise.inject.spi.PassivationCapable;
import javax.enterprise.util.AnnotationLiteral;

import org.jboss.weld.environment.se.Weld;

/**
* This custom {@link Bean} implementation is useful for mocking.
* <p>
Expand Down Expand Up @@ -70,8 +72,8 @@ public static <T> Builder<T> builder() {
}

/**
* A convenient method to create a {@link Bean} with default values (see also {@link #builder()}). Additionaly, the specified bean types are added to the set
* of bean types and {@link Bean#create(CreationalContext)} will always return the specified bean instance.
* A convenient method to create a {@link Bean} with default values (see also {@link #builder()}). Additionaly, the specified bean types are added to the
* set of bean types and {@link Bean#create(CreationalContext)} will always return the specified bean instance.
*
* @param beanInstance
* @param beanTypes
Expand All @@ -87,6 +89,8 @@ public static <T> Bean<T> of(T beanInstance, Type... beanTypes) {

private final boolean alternative;

private final boolean selectForSyntheticBeanArchive;

private final String name;

private final Set<Annotation> qualifiers;
Expand All @@ -101,19 +105,22 @@ public static <T> Bean<T> of(T beanInstance, Type... beanTypes) {

private final String id;

private MockBean(Set<Class<? extends Annotation>> stereotypes, boolean alternative, String name,
Set<Annotation> qualifiers, Set<Type> types, Class<? extends Annotation> scope,
CreateFunction<T> createCallback, DestroyFunction<T> destroyCallback) {
private final Class<?> beanClass;

private MockBean(Class<?> beanClass, Set<Class<? extends Annotation>> stereotypes, boolean alternative, boolean selectForSyntheticBeanArchive, String name,
Set<Annotation> qualifiers, Set<Type> types, Class<? extends Annotation> scope, CreateFunction<T> createCallback,
DestroyFunction<T> destroyCallback) {
this.beanClass = beanClass;
this.stereotypes = stereotypes;
this.alternative = alternative;
this.selectForSyntheticBeanArchive = selectForSyntheticBeanArchive;
this.name = name;
this.qualifiers = qualifiers;
this.types = types;
this.scope = scope;
this.createCallback = createCallback;
this.destroyCallback = destroyCallback;
this.id = new StringBuilder().append(MockBean.class.getName()).append("_")
.append(SEQUENCE.incrementAndGet()).toString();
this.id = new StringBuilder().append(MockBean.class.getName()).append("_").append(SEQUENCE.incrementAndGet()).toString();
}

@Override
Expand All @@ -130,7 +137,7 @@ public void destroy(T instance, CreationalContext<T> creationalContext) {

@Override
public Class<?> getBeanClass() {
return WeldCDIExtension.class;
return beanClass;
}

@Override
Expand Down Expand Up @@ -173,6 +180,16 @@ public boolean isAlternative() {
return alternative;
}

/**
* Initiator should use {@link #getBeanClass()} to select the alternative. Also the alternative should only be selected if {@link #isAlternative()} also
* returns <code>true</code>.
*
* @return <code>true</code> if the initiator should select the bean for the synthetic bean archive
*/
boolean isSelectForSyntheticBeanArchive() {
return selectForSyntheticBeanArchive;
}

@Override
public String getId() {
return id;
Expand All @@ -187,10 +204,14 @@ public String getId() {
*/
public static class Builder<T> {

private Class<?> beanClass;

private Set<Class<? extends Annotation>> stereotypes;

private boolean alternative;

private boolean selectForSyntheticBeanArchive;

private String name;

private Set<Annotation> qualifiers;
Expand All @@ -211,6 +232,18 @@ private Builder() {
this.scope = Dependent.class;
this.types = new HashSet<>();
this.types.add(Object.class);
this.beanClass = WeldCDIExtension.class;
}

/**
*
* @param beanClass
* @return self
* @see Bean#getBeanClass()
*/
public Builder<T> beanClass(Class<?> beanClass) {
this.beanClass = beanClass;
return this;
}

/**
Expand Down Expand Up @@ -270,6 +303,40 @@ public Builder<T> alternative(boolean value) {
return this;
}

/**
* The bean is an alternative and should be automatically selected for the synthetic bean archive.
*
* <p>
* Users are encouraged to specify {@link #beanClass(Class)} when using this method. The bean class is used to determine which alternative beans are
* selected for a bean archive. By default, all mock beans share the same bean class - {@code org.jboss.weld.junit.WeldCDIExtension}.
* </p>
*
* @param value
* @return self
* @see Bean#isAlternative()
* @see Weld#addAlternative(Class)
* @see #selectedAlternative(Class)
*/
public Builder<T> selectedAlternative() {
alternative(true);
this.selectForSyntheticBeanArchive = true;
return this;
}

/**
* The bean has the given bean class, is an alternative and should be automatically selected for the synthetic bean archive.
*
* @param beanClass
* @return self
* @see #selectedAlternative()
* @see #beanClass(Class)
*/
public Builder<T> selectedAlternative(Class<?> beanClass) {
selectedAlternative();
beanClass(beanClass);
return this;
}

/**
*
* @param stereotypes
Expand Down Expand Up @@ -333,8 +400,8 @@ public MockBean<T> build() {
if (qualifiers.size() == 1) {
qualifiers.add(DefaultLiteral.INSTANCE);
}
return new MockBean<>(stereotypes, alternative, name, qualifiers, types, scope,
createCallback, destroyCallback);
return new MockBean<>(beanClass, stereotypes, alternative, selectForSyntheticBeanArchive, name, qualifiers, types, scope, createCallback,
destroyCallback);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2017, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.junit4.bean;

import static org.junit.Assert.assertEquals;

import javax.enterprise.context.Dependent;

import org.jboss.weld.junit.MockBean;
import org.jboss.weld.junit4.WeldInitiator;
import org.junit.Rule;
import org.junit.Test;

/**
*
* @author Martin Kouba
*/
public class AlternativeMockBeanTest {

@Rule
public WeldInitiator weld = WeldInitiator.from(SimpleService.class)
.addBeans(MockBean.builder().types(MyService.class).selectedAlternative(CoolService.class).create(c -> new CoolService()).build()).build();

@Test
public void testAlternativeBeanSelected() {
assertEquals(1000, weld.select(MyService.class).get().doBusiness());
}

interface MyService {

int doBusiness();

}

@Dependent
static class SimpleService implements MyService {

@Override
public int doBusiness() {
return 0;
}
}

static class CoolService implements MyService {

@Override
public int doBusiness() {
return 1000;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2017, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.junit5.bean;

import javax.enterprise.context.Dependent;

import org.jboss.weld.junit.MockBean;
import org.jboss.weld.junit5.EnableWeld;
import org.jboss.weld.junit5.WeldInitiator;
import org.jboss.weld.junit5.WeldSetup;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
*
* @author Martin Kouba
*/
@EnableWeld
public class AlternativeMockBeanTest {

@WeldSetup
public WeldInitiator weld = WeldInitiator.from(SimpleService.class)
.addBeans(MockBean.builder().types(MyService.class).selectedAlternative().beanClass(CoolService.class).create(c -> new CoolService()).build())
.build();

@Test
public void testAlternativeBeanSelected() {
Assertions.assertEquals(1000, weld.select(MyService.class).get().doBusiness());
}

interface MyService {

int doBusiness();

}

@Dependent
static class SimpleService implements MyService {

@Override
public int doBusiness() {
return 0;
}
}

static class CoolService implements MyService {

@Override
public int doBusiness() {
return 1000;
}
}

}

0 comments on commit 838c354

Please sign in to comment.