Skip to content

Commit

Permalink
Add integration test instead of Main class for DI Exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
lamfalusy committed Oct 18, 2020
1 parent 07ce27e commit 5f9545e
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 74 deletions.
27 changes: 17 additions & 10 deletions week-8/dependency-injection-framework/pom.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.epam.training</groupId>
<artifactId>unideb-prog2-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<parent>
<groupId>com.epam.training</groupId>
<artifactId>unideb-prog2-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>

<artifactId>dependency-injection-framework</artifactId>
<artifactId>dependency-injection-framework</artifactId>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
</dependencies>

</project>

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
public interface DiContext {

public void addBean(String beanName, Object bean);

public <T> Optional<T> getBean(String beanName, Class<T> clazz);

public <T> Optional<T> getBean(Class<T> clazz);

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
public @interface Qualifier {

public String name();

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ public class DiContextBuilder {

public DiContext build(Configuration contextConfiguration) {
DiContext context = new DiContextImpl();

List<BeanDefinition> beanDefinitions = new LinkedList<BeanDefinition>();

for (Method method : contextConfiguration.getClass().getMethods()) {
if (isAnnotatedWithBean(method)) {
List<BeanDefinitionParameter> beanDependencies = new LinkedList<DiContextBuilder.BeanDefinitionParameter>();
Expand All @@ -31,36 +31,37 @@ public DiContext build(Configuration contextConfiguration) {
}
beanDependencies.add(new BeanDefinitionParameter<>(name, parameter.getType()));
}
beanDefinitions.add(new BeanDefinition(method.getName(), method.getReturnType(), method, beanDependencies));
beanDefinitions
.add(new BeanDefinition(method.getName(), method.getReturnType(), method, beanDependencies));
}
}

int beanDefinitionsSize = beanDefinitions.size();
context.addBean("context", context);

while (beanDefinitions.size() > 0) {
List<BeanDefinition> resolvedBeanDefinitions = new LinkedList<>();
List<BeanDefinition> resolvedBeanDefinitions = new LinkedList<>();
for (BeanDefinition beanDefinition : beanDefinitions) {
if (isBeanDefinitionResolvable(beanDefinition, context)) {
context.addBean(beanDefinition.name, createBean(beanDefinition, context, contextConfiguration));
resolvedBeanDefinitions.add(beanDefinition);
}
}
beanDefinitions.removeAll(resolvedBeanDefinitions);

if (beanDefinitionsSize == beanDefinitions.size()) {
throw new IllegalArgumentException("Circular dependency!");
} else {
beanDefinitionsSize = beanDefinitions.size();
}
}

return context;
}

private Object createBean(BeanDefinition beanDefinition, DiContext context, Object contextConfiguration) {
List<Object> dependencies = new ArrayList<>(beanDefinition.dependencies.size());

for (BeanDefinitionParameter parameter : beanDefinition.dependencies) {
Optional<Object> dependency;
if (parameter.name != null) {
Expand All @@ -70,7 +71,7 @@ private Object createBean(BeanDefinition beanDefinition, DiContext context, Obje
}
dependencies.add(dependency.get());
}

try {
return beanDefinition.builderMethod.invoke(contextConfiguration, dependencies.toArray());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Expand Down Expand Up @@ -101,13 +102,13 @@ private boolean isAnnotatedWithBean(Method method) {
}
return false;
}

private class BeanDefinition {
String name;
Class type;
Method builderMethod;
List<BeanDefinitionParameter> dependencies;

public BeanDefinition(String name, Class type, Method builderMethod,
List<BeanDefinitionParameter> dependencies) {
super();
Expand All @@ -117,16 +118,16 @@ public BeanDefinition(String name, Class type, Method builderMethod,
this.dependencies = dependencies;
}
}

private class BeanDefinitionParameter<T> {
String name;
Class<T> type;

public BeanDefinitionParameter(String name, Class<T> type) {
super();
this.name = name;
this.type = type;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class DiContextImpl implements DiContext {

private Map<String, Object> context = new HashMap<>();
private Map<Class<?>, List<Object>> contextMappedByType = new HashMap<>();

public void addBean(String beanName, Object bean) {
if (context.containsKey(beanName)) {
throw new IllegalArgumentException("Bean has been already created: " + beanName);
Expand All @@ -26,7 +26,7 @@ public void addBean(String beanName, Object bean) {
contextMappedByType.put(bean.getClass(), objectList);
}
}

@SuppressWarnings("unchecked")
public <T> Optional<T> getBean(String beanName, Class<T> clazz) {
Optional<T> ret = null;
Expand All @@ -49,8 +49,8 @@ public <T> Optional<T> getBean(Class<T> clazz) {
throw new IllegalArgumentException("There are multiple bean available for type: " + clazz);
} else {
ret = Optional.of((T) objestList.get(0));
}
}
return ret;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.epam.training.di.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Optional;

import org.junit.jupiter.api.Test;

import com.epam.training.di.Configuration;
import com.epam.training.di.DiContext;
import com.epam.training.di.annotation.Bean;
import com.epam.training.di.annotation.Qualifier;

public class DiContextImplIntegrationTest {

private DiContext context = new DiContextBuilder().build(new DiContextImplIntegrationTest.ContextConfig());

@Test
public void testGetBeanShouldReturnWithStringAWhenThisBeanExists() {
// Given
String expected = "StringA";

// When
Optional<String> actual = context.getBean("stringBeanA", String.class);

// Then
assertTrue(actual.isPresent());
assertEquals(expected, actual.get());
}

@Test
public void testGetBeanShouldReturnWithStringBWhenThisBeanExists() {
// Given
String expected = "StringB";

// When
Optional<String> actual = context.getBean("stringBeanB", String.class);

// Then
assertTrue(actual.isPresent());
assertEquals(expected, actual.get());
}

@Test
public void testGetBeanShouldReturnWithIntegerBeanWhenGetIsCalledWithTypeOnly() {
// Given
Integer expected = 10;

// When
Optional<Integer> actual = context.getBean(Integer.class);

// Then
assertTrue(actual.isPresent());
assertEquals(expected, actual.get());
}

@Test
public void testGetBeanShouldReturnWithStringBuilderBeanWhenGetIsCalledWithTypeOnly() {
// Given
String expected = "StringA10";

// When
Optional<StringBuilder> actual = context.getBean(StringBuilder.class);

// Then
assertTrue(actual.isPresent());
assertEquals(expected, actual.get().toString());
}

@Test
public void testGetBeanShouldReturnWithOptionalEmptyWhenBeanDoesNotExist() {
// Given

// When
Optional<String> actual = context.getBean("stringBean", String.class);

// Then
assertTrue(actual.isEmpty());
}

@Test
public void testGetBeanShouldThrowAnExceptionWhenMoreBeansAreAvailable() {
// Given

// When Then
assertThrows(IllegalArgumentException.class, () -> context.getBean(String.class));
}

public static class ContextConfig implements Configuration {

@Bean
public String stringBeanA() {
return "StringA";
}

@Bean
public String stringBeanB() {
return "StringB";
}

@Bean
public Integer integerBean() {
return 10;
}

@Bean
public StringBuilder stringBuilder(@Qualifier(name = "stringBeanA") String string, Integer integer) {
return new StringBuilder(string).append(integer);
}

}

}

0 comments on commit 5f9545e

Please sign in to comment.