Best way to unit test this method? - java

I have the following class
public class Multiplier {
private static Map<Integer, Float> map;
private static final float DEFAULT_MULTIPLIER = 4.4F;
static {
// This map is actually populated by reading from a file. This is an example on how the map looks like.
map = new HashMap<>();
map.put(1, "3.5F");
map.put(2, "5.8F");
map.put(3, "2.7F");
}
public static float getMultiplier(Integer id) {
return map.getOrDefault(id, DEFAULT_MULTIPLIER);
}
}
I have another class
public class MultiplierUser {
private integer id;
private float value;
private float result;
public MultiplierUser(int id, float value) {
this.id = id;
this.value = value;
}
public void setResult() {
result = value * Multiplier.getMultiplier(this.id);
}
public float getResult() {
return this.result;
}
}
What's the best way to test this method?
Should I get the expected value by calling the method and then asserting?
public testMethod() {
MultiplierUser multiplierUser = new MultiplierUser(1, 10F);
multiplierUser.setResult();
float expected = Multiplier.getMultiplier(1) * 10F;
Assert.assertEquals(expected, multiplierUser.getResult());
}
Or mock?
public testMethod() {
MultiplierUser multiplierUser = new MultiplierUser(1, 10F);
Mockito.mock(Multiplier.class);
when(mock.getMultiplier(1)).thenReturn(1.5F);
multiplierUser.setResult();
float expected = 1.5F * 10F;
Assert.assertEquals(expected, multiplierUser.getResult());
}
I can't understand which would be the better way to test this method? If I use the former, I'm basically calling the method myself and getting the result. But if there's an issue with the method in the future, the test will keep succeeding. If I'm using a mock, then I'm technically not testing the method and the value it returns. I'm confused. Please help.

To test the setResult method, mocking the Multiplier is sufficient.
The methods setResult and getMultiplier are pretty straight forward in this case.
But let's consider a scenario where complex operations are involved:
public class A {
public int foo1() {
//some complex operations
}
}
public class B {
public int foo2() {
A a = new A();
int val = a.foo1();
//some complex operations
}
}
Now to test foo2(), it makes more sense to mock the class A and use thenReturn to get some sample output rather than testing the entire foo1() method in the test for foo2(). This ensures that you are only testing the corresponding units of code pertaining to the method under test.
Unit tests should be designed such that they are simple, readable and deals with one logic at a time.

Related

Reducing cyclomatic complexity

I have a class with some 20+ fields of the same type that are populated during different stages of the object lifecycle.
One of the class methods should return the field value based on the field name.
So far I have something like this:
public String getFieldValue(String fieldName){
switch (fieldName.toLowerCase(){
case "id": return getId();
case "name": return getName();
.....
the problem with this is high cyclomatic complexity.
What would be the easiest way to tackle this?
Edit: Thanks to #Filippo Possenti for his comment
Instead of a switch, you can use a Map.
Here is an example.
static interface C {
String getA();
String getB();
String getC();
}
#FunctionalInterface
static interface FieldGetter {
String get(C c);
}
static Map<String, FieldGetter> fields = Map.of(
"a", C::getA,
"b", C::getB,
"c", C::getC
);
static String getField(C object, String fieldNameToRetrieve) {
var getter = fields.get(fieldNameToRetrieve);
if(getter == null) {
throw new IllegalArgumentException("unknown field");
}
return getter.get(object);
}
Why don't you use reflexion or an existing library for this ? (Or why do you even have this kind of method)
In theory you could reduce the getFieldValue() method complexity by:
storing the getter method reference as Producer<?> in Map<String, Producer<?>>
using reflection to lookup fields
using 3rd party library that supports querying the bean by property name e.g. commons-beanutils.
Each of these approaches will however increase the getFieldValue() method complexity and potentially reduce the performance. Both are worse problems than high complexity.
It feels like you should review why you need the getFieldValue() method in the first place, maybe it should be a Map<String, ?>?
Assuming that the fieldName possible values match the getters on the bean, you can use Apache's BeanUtils:
https://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/PropertyUtils.html#getSimpleProperty-java.lang.Object-java.lang.String-
Basically, you could do something like this:
public String getFieldValue(String fieldName){
return PropertyUtils.getSimpleProperty(fieldName.toLowerCase());
}
This is more about improving code readability than improving cyclomatic complexity so if it's pure performance what you're after, this may not be your solution.
If pure performance is what you're after, you could try and leverage lambdas and a Map.
import java.util.Map;
import java.util.HashMap;
import java.util.function.Function;
public class HelloWorld{
public static class MyClass {
private static Map<String, Function<MyClass, Object>> descriptor;
static {
descriptor = new HashMap<>();
descriptor.put("id", MyClass::getId);
descriptor.put("name", MyClass::getName);
}
private String id;
private String name;
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setId(String value) {
id = value;
}
public void setName(String value) {
name = value;
}
public Object getFieldValue(String fieldName) {
Function fn = descriptor.get(fieldName);
return fn.apply(this);
}
}
public static void main(String []args){
MyClass mc = new MyClass();
mc.setId("hello");
mc.setName("world");
System.out.println(mc.getFieldValue("id") + " " + mc.getFieldValue("name"));
}
}
To note that in the above example the cyclomatic complexity is somewhat still there, but it's moved in the class' static initialiser. This means that you'll suffer a modest penalty during application startup but enjoy higher performance in subsequent calls of getFieldValue.
Also, if performance is what you're after you may want to eliminate the need for toLowerCase... which in my example I removed.
Instead of the switch or using a Map, you can use an enum.
enum FieldExtractor implements Function<YourClass, String> {
ID(YourClass::getId),
NAME(YourClass::getName); // and so on
private final Function<YourClass, String> delegate;
FieldExtractor(Function<YourClass, String> delegate) {
this.delegate = delegate;
}
#Override public String apply(YourClass extractFrom) {
return delegate.apply(extractFrom);
}
static FieldExtractor fromString(String name) {
return Stream.of(FieldExtractor.values())
.filter(fe -> fe.name().equalsIgnoreCase(name))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
Now you can use
public String getFieldValue(String fieldName) {
return FieldExtractor.fromString(fieldName).apply(this);
}
in your client code.

How to parse values from a hashmap to a variable

So I'm trying to create a class which only stores a hashmap and it's values as I will need to access them from another class at some point and it's values could change at any point. Below is an example of what I'm trying
PriceInfo.java
public class PriceInfo {
public static HashMap PriceInformation() {
HashMap<String, Double> trainerPrice = new HashMap<>();
trainerPrice.put("Nike", 199.99);
trainerPrice.put("Adidas", 150.99);
return trainerPrice;
}
}
DiscountChecker.java
public class DiscountChecker {
public boolean AllowDiscount(String discountCode, String tBrand) {
if (discountCode.equals("Hello")) {
double tPrice = PriceInfo.PriceInformation().get(tBrand);
double discountedPrice = 0.8 * tPrice;
return true;
} else {
return false;
}
}
}
At the moment, I keep getting an error saying incompatible types and double is required.
The error is on this line double tPrice = PriceInfo.PriceInformation().get(tBrand);
Change the signature of your method from
public static double PriceInformation ()
to
public static Map<String, Double> PriceInformation ()
Aside: Please follow proper naming conventions and change your method names to start with lowercase.

Modify an instance variable within the Main class or main method

I would like to be able to modify the value of a local variable defined in a constructor within the class via the main driver class at some point while running the program. How would I be able to achieve this?
Here is a sample of a constructor that I am using.
public Scale()
{
weight = 0;
unit = "kg";
}
I'd like to modify the value of weight at a point while running the program in the driver.
It sounds like you're wanting to give the class a method that would allow outside code to be able to change or "mutate" the state of the fields of the class. Such "mutator" methods are commonly used in Java, such as "setter" methods. Here, public void setWeight(int weight):
public void setWeight(int weight) {
this.weight = weight;
}
The best way to allow that would probably be through a method. It could be something as straightforward as setWeight(), or something more complicated like a method for adding items to the scale...
public class Scale {
private float weight = 0;
private String unit = "kg";
public void setWeight(float weight) {
this.weight = weight;
}
public void addItem(Item i) { // Assumes that Item is an interface defined somewhere else...
this.weight += i.getWeight();
}
public static void main(String[] args) {
Scale s = new Scale();
s.setWeight(4.0F); // sets the weight to 4kg
s.addItem(new Item() {
#Override
public float getWeight() {
return 2.0F;
}
}); // Adds 2kg to the previous 4kg -- total of 6kg
}
}

Can a method return a set of different return types in a succinct way?

How would I get the string Percent from getData? Is there a way to have getData return multiple strings and request only the ones I choose from it, like if I wanted the percentage number I would call getData("http://woot.com").Percentage?
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class Wooot {
public static void main(String[] args) throws IOException, InterruptedException {
needData();
Report();
}
public static void Report() throws InterruptedException, IOException{
while (needData() == true)
{
System.out.println(getData("http://woot.com"));
Thread.sleep(5000);
}
}
public static boolean needData(){
return true;
}
public static String getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return name;
}
}
You can make a class to hold the fields you want back:
class SomeData {
private final String percent;
private final String name;
public SomeData(String percent, String name) {
this.percent = percent;
this.name = name;
}
public String getName() {return name;}
public String getPercent() {return percent;}
}
It is a valid point that getters here are not an absolute necessity. Since Java doesn't follow the universal access principle introducing them later can be a little awkward, so I add them in up front. But mostly I do it because my co-workers are used to seeing the getters and I try to avoid weirding them out too much.
You could also add a convenience constructor:
public SomeData(Document document) {
this(doc.select(".percent-remaining").first().text(),
doc.select("h2").first().text());
}
This way retrieving the data fields would be in a different place from the connection logic, so you don't have the SRP violation of having multiple reasons for a class to change.
Using some general purpose collection like a Tuple or Map is an option. Tuples are ugly because the names of the fields get discarded. With maps, if entries have different types then the compile-time type-checking gets lost.
Alternatively you could return the Document object instead. I'm not sure introducing a new data holder class here is better than using Document.
Struct-like object return
There are a few ways you can get "effective" multiple returns. I usually use a lightweight struct-like class to support this
public static String getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return new ImportantData(name,percent) ;
}
class ImportantData{
public final String name;
public final String percent; //not sure why the percentage is a string
public ImportantData(String name, String percent){
this.name=name;
this.percentage=percentage;
}
}
This is one of the rare cases where getters add no value and a final field makes more sense.
Store objects passed as arguments
An alternative I have also seen is to pass a store object to the method. This only works with mutable objects and is far less clear than the Struct-like object return. Make sure to produce clear documentation if using this approach.
public static String getData(String url, Vector3d store) throws IOException {
store.x=1;
store.y=2;
store.z=3;
return "someOtherString" ;
}
You can create a class Data with an attribute Percentage. Something like:
public class Data {
private String percentage;
public Data() {
}
public String getPercentage() {
return percentage;
}
public void setPercentage(String percentage) {
this.percentage = percentage;
}
}
Then, you can call:
Data d = wooot.getData();
String percentage = d.getPercentage();
Without paying attention to what you are trying to accomplish, I think the "general purpose" solution for this problem would be to return an instance of a new class that wrapped both values.
public static class DataResults
{
private final String percent;
private final String name;
public DataResults(String percent, String name) {
super();
this.percent = percent;
this.name = name;
}
public String getPercent() {
return percent;
}
public String getName() {
return name;
}
}
public static DataResults getData(String url) throws IOException {
Document doc = Jsoup
.connect(url)
.get();
String percent = doc.select(".percent-remaining").first().text();
String name = doc.select("h2").first().text();
return new DataResults(percent, name);
}
When you think you need multiple results from a method, you're really trying to represent something conceptually more complicated than two separate values. You're actually trying to represent two results and the relationship between them. Take, for instance, the idea of integer division, when you care about both the result and the remainder. The first option would be to just define two separate methods, divide(), and mod(). The problem is now a) you do the same operation twice, and b) you separate obviously connected logic. You're not actually trying to return two pieces of data, you're trying to return one, more complicated result.
public class DivMod {
public final int result;
public final int remainder;
// standard constructor, getters aren't strictly necessary in such a simple class
}
public static DivMod divMod(int dividend, int divisor) {
// compute remainder, result
return new DivMod(remainder, result);
}
This snippet hopefully makes it clear that there's often there's something even better you could do - do the computation in the object:
public class DivMod {
private final int dividend, divisor, result, remainder;
public DivMod(int dividend, int divisor) {
this.dividend = dividend;
this.divisor = divisor;
// calculate and set result and remainder
}
// standard getters
}
Now we've really compartmentalized what we're trying to do with proper Object Oriented Programming. There's no need for a static method, and all the logic is clearly in one place. Even better, we avoid the above case where a meaningless DivMod is constructed (one that doesn't actually represent a division result). We guarantee that every DivMod instance is an immutable result of integer division.
There are two standard alternatives to the above, both of which are anti-patterns. The first is to return an array or a Collection, and the second is to define some sort of general Tuple class that holds multiple arbitrary data types. While tuples at least offer the benefit of being a fixed size, and the ability to hold different types in the same object, they are terribly poor alternatives to a proper OOP design. Guava offers some insight in their Idea Graveyard, as well.
See also #RichardTingle's suggestion of passing a mutable object into your method in order to update it with additional data, but consider this strictly a last resort option; it generally introduces far more confusion than benefit.
You can use String[] and return an Array of Strings.

Capturing method parameter in jMock to pass to a stubbed implementation

I wish to achieve the following behavior.
My class under test has a dependency on some other class, I wish to mock this dependency with jMock. Most of the methods would return some standard values, but there is one method, where I wish to make a call to a stubbed implementation, I know I can call this method from the will(...) but I want the method to be called by the exact same parameters that were passed to the mocked method.
Test
#Test
public void MyTest(){
Mockery context = new Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
IDependency mockObject = context.mock(IDependency.class);
Expectations exp = new Expectations() {
{
allowing(mockObject).methodToInvoke(????);
will(stubMethodToBeInvokedInstead(????));
}
};
}
Interface
public interface IDependency {
public int methodToInvoke(int arg);
}
Method to be called instead
public int stubMethodToBeInvokedInstead(int arg){
return arg;
}
So how do I capture the parameter that were passed to the method being mocked, so I could pass them to the stubbed method instead?
EDIT
Just to give another example, let's say I wish to mock the INameSource dependency in the following (C#) code, to test the class Speaker
public class Speaker
{
private readonly string firstName;
private readonly string surname;
private INameSource nameSource ;
public Speaker(string firstName, string surname, INameSource nameSource)
{
this.firstName = firstName;
this.surname = surname;
this.nameSource = nameSource;
}
public string Introduce()
{
string name = nameSource.CreateName(firstName, surname);
return string.Format("Hi, my name is {0}", name);
}
}
public interface INameSource
{
string CreateName(string firstName, string surname);
}
This is how it can be done in Rhino Mocks for C# I understand it can't be as easy as this since delegates are missing in Java
The solution from Duncan works well, but there is even a simpler solution without resort to a custom matcher. Just use the Invocation argument that is passed to the CustomActions invoke method. At this argument you can call the getParameter(long i) method that gives you the value from the call.
So instead of this
return matcher.getLastValue();
use this
return (Integer) invocation.getParameter(0);
Now you don't need the StoringMatcher anymore: Duncans example looks now like this
#RunWith(JMock.class)
public class Example {
private Mockery context = new JUnit4Mockery();
#Test
public void Test() {
final IDependency mockObject = context.mock(IDependency.class);
context.checking(new Expectations() {
{
// No custom matcher required here
allowing(mockObject).methodToInvoke(with(any(Integer.class)));
// The action will return the first argument of the method invocation.
will(new CustomAction("returns first arg") {
#Override
public Object invoke(Invocation invocation) throws Throwable {
return (Integer) invocation.getParameter(0);
}
});
}
});
Integer test1 = 1;
Integer test2 = 1;
// Confirm the object passed to the mocked method is returned
Assert.assertEquals((Object) test1, mockObject.methodToInvoke(test1));
Assert.assertEquals((Object) test2, mockObject.methodToInvoke(test2));
}
public interface IDependency {
public int methodToInvoke(int arg);
}
Like Augusto, I'm not convinced this is a good idea in general. However, I couldn't resist having a little play. I created a custom matcher and a custom action which store and return the argument supplied.
Note: this is far from production-ready code; I just had some fun. Here's a self-contained unit test which proves the solution:
#RunWith(JMock.class)
public class Example {
private Mockery context = new JUnit4Mockery();
#Test
public void Test() {
final StoringMatcher matcher = new StoringMatcher();
final IDependency mockObject = context.mock(IDependency.class);
context.checking(new Expectations() {
{
// The matcher will accept any Integer and store it
allowing(mockObject).methodToInvoke(with(matcher));
// The action will pop the last object used and return it.
will(new CustomAction("returns previous arg") {
#Override
public Object invoke(Invocation invocation) throws Throwable {
return matcher.getLastValue();
}
});
}
});
Integer test1 = 1;
Integer test2 = 1;
// Confirm the object passed to the mocked method is returned
Assert.assertEquals((Object) test1, mockObject.methodToInvoke(test1));
Assert.assertEquals((Object) test2, mockObject.methodToInvoke(test2));
}
public interface IDependency {
public int methodToInvoke(int arg);
}
private static class StoringMatcher extends BaseMatcher<Integer> {
private final List<Integer> objects = new ArrayList<Integer>();
#Override
public boolean matches(Object item) {
if (item instanceof Integer) {
objects.add((Integer) item);
return true;
}
return false;
}
#Override
public void describeTo(Description description) {
description.appendText("any integer");
}
public Integer getLastValue() {
return objects.remove(0);
}
}
}
A Better Plan
Now that you've provided a concrete example, I can show you how to test this in Java without resorting to my JMock hackery above.
Firstly, some Java versions of what you posted:
public class Speaker {
private final String firstName;
private final String surname;
private final NameSource nameSource;
public Speaker(String firstName, String surname, NameSource nameSource) {
this.firstName = firstName;
this.surname = surname;
this.nameSource = nameSource;
}
public String introduce() {
String name = nameSource.createName(firstName, surname);
return String.format("Hi, my name is %s", name);
}
}
public interface NameSource {
String createName(String firstName, String surname);
}
public class Formal implements NameSource {
#Override
public String createName(String firstName, String surname) {
return String.format("%s %s", firstName, surname);
}
}
Then, a test which exercises all the useful features of the classes, without resorting to what you were originally asking for.
#RunWith(JMock.class)
public class ExampleTest {
private Mockery context = new JUnit4Mockery();
#Test
public void testFormalName() {
// I would separately test implementations of NameSource
Assert.assertEquals("Joe Bloggs", new Formal().createName("Joe", "Bloggs"));
}
#Test
public void testSpeaker() {
// I would then test only the important features of Speaker, namely
// that it passes the right values to the NameSource and uses the
// response correctly
final NameSource nameSource = context.mock(NameSource.class);
final String firstName = "Foo";
final String lastName = "Bar";
final String response = "Blah";
context.checking(new Expectations() {
{
// We expect one invocation with the correct params
oneOf(nameSource).createName(firstName, lastName);
// We don't care what it returns, we just need to know it
will(returnValue(response));
}
});
Assert.assertEquals(String.format("Hi, my name is %s", response),
new Speaker(firstName, lastName, nameSource).introduce());
}
}
JMock doesn't support your use case (or any other mocking framework I know of in java).
There's a little voice in my head that says that what you're trying to do is not ideal and that your unit test might be to complicated (maybe it's testing too much code/logic?). One of the problems I see, is that you don't know which values those mocks need to return and you're plugging something else, which might make each run irreproducible.

Categories

Resources