* BAEL-7436: Initial Unit Tests

* BAEL-7436: Added an Example with Service

* BAEL-7436: Cleanup and test fixes

* BAEL-7436: Test rename

* BAEL-7436: Cleanup

* BAEL-7436: Fix pom

* BAEL-7436: Test rename
This commit is contained in:
Eugene Kovko 2024-01-04 18:50:50 +01:00 committed by GitHub
parent 6114e0534f
commit 61e5d8cd76
17 changed files with 541 additions and 0 deletions

View File

@ -14,4 +14,20 @@
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache.commons.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
<properties>
<apache.commons.version>3.14.0</apache.commons.version>
</properties>
</project>

View File

@ -0,0 +1,26 @@
package com.baeldung.nullconversion;
public class Address implements Cloneable {
private ZipCode zipCode;
public ZipCode getZipCode() {
return zipCode;
}
public void setZipCode(ZipCode zipCode) {
this.zipCode = zipCode;
}
@Override
protected Address clone() {
Address address;
try {
address = ((Address) super.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
zipCode = zipCode.clone();
return address;
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.nullconversion;
import java.util.Objects;
public class Delivery {
private String message;
public Delivery(String message) {
this.message = message;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Delivery delivery = (Delivery) o;
return Objects.equals(message, delivery.message);
}
@Override
public int hashCode() {
return message != null ? message.hashCode() : 0;
}
public static Delivery freeDelivery() {
return new Delivery("Free delivery");
}
}

View File

@ -0,0 +1,6 @@
package com.baeldung.nullconversion;
public interface DeliveryService {
Delivery calculateDeliveryForPerson(Long id);
}

View File

@ -0,0 +1,26 @@
package com.baeldung.nullconversion;
public class Person implements Cloneable {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
protected Person clone() {
Person person;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
address = address.clone();
return person;
}
}

View File

@ -0,0 +1,27 @@
package com.baeldung.nullconversion;
public class ZipCode implements Cloneable {
private String code;
public ZipCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
@Override
protected ZipCode clone() {
try {
return (ZipCode) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,130 @@
package com.baeldung.nullconversion;
import static java.util.Objects.requireNonNullElse;
import static java.util.Objects.requireNonNullElseGet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import com.google.common.base.MoreObjects;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
class NullConversionUnitTest {
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenIfWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = defaultValue;
if (givenValue != null) {
actual = givenValue;
}
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsSupplierProvider.class)
void givenIfWhenNotNullThenReturnsDefault(String givenValue, String expected,
Supplier<String> expensiveSupplier) {
String actual;
if (givenValue != null) {
actual = givenValue;
} else {
actual = expensiveSupplier.get();
}
assertDefaultConversion(givenValue, expected, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenTernaryWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = givenValue != null ? givenValue : defaultValue;
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsSupplierProvider.class)
void givenLazyTernaryWhenNotNullThenReturnsDefault(String givenValue, String expected,
Supplier<String> expensiveSupplier) {
String actual = givenValue != null ? givenValue : expensiveSupplier.get();
assertDefaultConversion(givenValue, expected, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenObjectsWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = requireNonNullElse(givenValue, defaultValue);
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsSupplierProvider.class)
void givenLazyObjectsWhenNotNullThenReturnsDefault(String givenValue, String expected,
Supplier<String> expensiveSupplier) {
String actual = requireNonNullElseGet(givenValue, expensiveSupplier);
assertDefaultConversion(givenValue, expected, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenOptionalWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = Optional.ofNullable(givenValue).orElse(defaultValue);
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsSupplierProvider.class)
void givenLazyOptionalWhenNotNullThenReturnsDefault(String givenValue, String expected,
Supplier<String> expensiveSupplier) {
String actual = Optional.ofNullable(givenValue).orElseGet(expensiveSupplier);
assertDefaultConversion(givenValue, expected, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenGuavaWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = MoreObjects.firstNonNull(givenValue, defaultValue);
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenGuavaOptionalWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = com.google.common.base.Optional.fromNullable(givenValue).or(defaultValue);
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsProvider.class)
void givenApacheWhenNotNullThenReturnsDefault(String givenValue, String defaultValue) {
String actual = ObjectUtils.firstNonNull(givenValue, defaultValue);
assertDefaultConversion(givenValue, defaultValue, actual);
}
@ParameterizedTest
@ArgumentsSource(ObjectsSupplierProvider.class)
void givenLazyApacheWhenNotNullThenReturnsDefault(String givenValue, String expected,
Supplier<String> expensiveSupplier) {
String actual = ObjectUtils.getFirstNonNull(() -> givenValue, expensiveSupplier);
assertDefaultConversion(givenValue, expected, actual);
}
@Test
void givenAllNullsWithObjectsWhenNotNullThenThrowException() {
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> requireNonNullElse(null, null));
}
private static void assertDefaultConversion(String given, String expected, String actual) {
if (given == null) {
assertThat(actual).isEqualTo(expected);
} else {
assertThat(actual).isEqualTo(given);
}
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.nullconversion;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class NullReturningPersonChainProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
Person person = new Person();
Address address = new Address();
ZipCode zipCode = new ZipCode("98-323");
address.setZipCode(zipCode);
person.setAddress(address);
return Stream.of(
Arguments.of(PersonMutatorUtil.cloneAndMutate(person, p -> p.getAddress().getZipCode().setCode(""))),
Arguments.of(PersonMutatorUtil.cloneAndMutate(person, p -> p.getAddress().setZipCode(null))),
Arguments.of(PersonMutatorUtil.cloneAndMutate(person, p -> p.setAddress(null)))
);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.nullconversion;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class ObjectsProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(null, "default"),
Arguments.of("not null", "default")
);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.nullconversion;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class ObjectsSupplierProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
Supplier<String> supplier = () -> "default";
return Stream.of(
Arguments.of(null, "default", supplier),
Arguments.of("not null", "default", supplier)
);
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.nullconversion;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import com.baeldung.nullconversion.service.OnePersonExplicitDeliveryService;
import com.baeldung.nullconversion.service.OnePersonGuavaOptionalDeliveryService;
import com.baeldung.nullconversion.service.OnePersonOptionalDeliveryService;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
class OnePersonDeliveryServiceUnitTest {
@ParameterizedTest
@ArgumentsSource(PersonProvider.class)
void givenMockDeliverServiceWhenNullValuesThenExplicitServiceHandleThem(Person person, Delivery expected) {
DeliveryService deliveryService = new OnePersonExplicitDeliveryService(person);
Delivery actual = deliveryService.calculateDeliveryForPerson(1L);
assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@ArgumentsSource(PersonProvider.class)
void givenMockDeliverServiceWhenNullValuesThenOptionalServiceHandleThem(Person person, Delivery expected) {
DeliveryService deliveryService = new OnePersonOptionalDeliveryService(person);
Delivery actual = deliveryService.calculateDeliveryForPerson(1L);
assertThat(actual).isEqualTo(expected);
}
@ParameterizedTest
@ArgumentsSource(NullReturningPersonChainProvider.class)
void givenMockDeliverServiceWhenNullValuesThenGuavaOptionalServiceThrowsException(Person person) {
DeliveryService deliveryService = new OnePersonGuavaOptionalDeliveryService(person);
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> deliveryService.calculateDeliveryForPerson(1L));
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.nullconversion;
import java.util.function.Consumer;
public class PersonMutatorUtil {
public static Person cloneAndMutate(Person person, Consumer<Person> mutator) {
Person clone = person.clone();
mutator.accept(clone);
return clone;
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.nullconversion;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class PersonProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
Person person = new Person();
Address address = new Address();
ZipCode zipCode = new ZipCode("98-323");
address.setZipCode(zipCode);
person.setAddress(address);
return Stream.of(
Arguments.of(person, Delivery.freeDelivery()),
Arguments.of(cloneAndMutate(person, p -> p.getAddress().getZipCode().setCode("")), null),
Arguments.of(cloneAndMutate(person, p -> p.getAddress().setZipCode(null)), null),
Arguments.of(cloneAndMutate(person, p -> p.setAddress(null)), null),
Arguments.of(null, null)
);
}
private static Person cloneAndMutate(Person person, Consumer<Person> mutator) {
Person clone = person.clone();
mutator.accept(clone);
return clone;
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.nullconversion.service;
import com.baeldung.nullconversion.Address;
import com.baeldung.nullconversion.Delivery;
import com.baeldung.nullconversion.DeliveryService;
import com.baeldung.nullconversion.Person;
import com.baeldung.nullconversion.ZipCode;
import java.util.Optional;
public abstract class MockOnePersonDeliveryServiceBase implements DeliveryService {
private final Person person;
public MockOnePersonDeliveryServiceBase(Person person) {
this.person = person;
}
@Override
public Delivery calculateDeliveryForPerson(Long id) {
Person person = getPersonById(id);
if (person != null && person.getAddress() != null && person.getAddress().getZipCode() != null) {
ZipCode zipCode = person.getAddress().getZipCode();
String code = zipCode.getCode();
return calculateDeliveryForZipCode(code);
}
return null;
}
public Delivery calculateDeliveryForPersonWithOptional(Long id) {
return Optional.ofNullable(getPersonById(id))
.map(Person::getAddress)
.map(Address::getZipCode)
.map(ZipCode::getCode)
.map(this::calculateDeliveryForZipCode)
.orElse(null);
}
protected Person getPersonById(Long id) {
return person;
}
protected Delivery calculateDeliveryForZipCode(String zipCode) {
if (zipCode == null || zipCode.isEmpty()) {
return null;
} else {
return Delivery.freeDelivery();
}
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.nullconversion.service;
import com.baeldung.nullconversion.Delivery;
import com.baeldung.nullconversion.Person;
import com.baeldung.nullconversion.ZipCode;
public class OnePersonExplicitDeliveryService extends MockOnePersonDeliveryServiceBase {
public OnePersonExplicitDeliveryService(Person person) {
super(person);
}
@Override
public Delivery calculateDeliveryForPerson(Long id) {
Person person = getPersonById(id);
if (person != null && person.getAddress() != null && person.getAddress().getZipCode() != null) {
ZipCode zipCode = person.getAddress().getZipCode();
String code = zipCode.getCode();
return calculateDeliveryForZipCode(code);
}
return null;
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.nullconversion.service;
import com.baeldung.nullconversion.Address;
import com.baeldung.nullconversion.Delivery;
import com.baeldung.nullconversion.Person;
import com.baeldung.nullconversion.ZipCode;
import com.google.common.base.Optional;
public class OnePersonGuavaOptionalDeliveryService extends MockOnePersonDeliveryServiceBase {
public OnePersonGuavaOptionalDeliveryService(Person person) {
super(person);
}
@Override
public Delivery calculateDeliveryForPerson(Long id) {
return Optional.fromNullable(getPersonById(id))
.transform(Person::getAddress)
.transform(Address::getZipCode)
.transform(ZipCode::getCode)
.transform(this::calculateDeliveryForZipCode)
.orNull();
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.nullconversion.service;
import com.baeldung.nullconversion.Address;
import com.baeldung.nullconversion.Delivery;
import com.baeldung.nullconversion.Person;
import com.baeldung.nullconversion.ZipCode;
import java.util.Optional;
public class OnePersonOptionalDeliveryService extends MockOnePersonDeliveryServiceBase {
public OnePersonOptionalDeliveryService(Person person) {
super(person);
}
@Override
public Delivery calculateDeliveryForPerson(Long id) {
return Optional.ofNullable(getPersonById(id))
.map(Person::getAddress)
.map(Address::getZipCode)
.map(ZipCode::getCode)
.map(this::calculateDeliveryForZipCode)
.orElse(null);
}
}