Test that method is called with proper parameters all across the software - java

I've just ran into a problem recently when a method in my service was called with wrong parameters. This caused some kind of outage, so I'm thinking about how to prevent that in the future.
So assuming that I have the following method:
public boolean doSomething(String param1, String param2);
I want to verify that each time this method is called (no matter where in my service), the param1 value is specific (e.g. only String1, String2 and String3 would be a valid parameter value for that.
Is there any technology/library/tool for that to verify this for instance in a unit test?
Update: as the accepted answer suggests, this is something that should not be covered through unit tests since unit tests are for behavioural testing. What would prevent the wrong call in the future is using Preconditions or just simple parameter check.

When possible you should leverage compile-time checks rather than deferring the tests to runtime. If there are only three legal values then perhaps param1 should be an enum rather than a String.
Unit tests are for verifying that a method behaves in a certain way. They treat the method like a black box and poke it from the outside. They don't help if you're concerned with how it is called. There you're inside the method and want to verify that the outside world is well-behaved. The way to do that is with run-time precondition checks at the start of the method.
public boolean doSomething(String param1, String param2) {
if (!Objects.equals(param1, "String1") &&
!Objects.equals(param1, "String2") &&
!Objects.equals(param1, "String3"))
{
throw IllegalArgumentException("param1 must be String1, 2, or 3");
}
...
}
Guava's Preconditions class can be helpful.
public boolean doSomething(String param1, String param2) {
Preconditions.checkArgument(
Objects.equals(param1, "String1") ||
Objects.equals(param1, "String2") ||
Objects.equals(param1, "String3"),
"param1 must be String1, 2, or 3"
);
...
}

Create an unit test that ensures that only some values are accepted by the method as param1 parameter at runtime.
Code a test with the two scenarios : valid and invalid cases.
For example in JUnit 5 :
#Test
public void doSomething(){
Assert.AssertTrue(new Foo().doSomething("String1", "anyValue");
Assert.AssertTrue(new Foo().doSomething("String2", "anyValue");
Assert.AssertTrue(new Foo().doSomething("String3", "anyValue");
}
#Test
public void doSomething_with_illegal_argument(){
Assert.assertThrows(IllegalArgumentException.class, () -> new Foo().doSomething("invalidValue", "anyValue"));
}
The test should fail as you actually don't guarantee that.
So then improve your actual implementation to make the test pass.
For example :
public boolean doSomething(String param1, String param2) {
if (!"String1".equals(param1) &&
!"String2".equals(param1) &&
!"String3".equals(param1) {
throw new IllegalArgumentException("param1 should be ...");
}
... // processing
}
I would add that a test unit cannot cover all failing cases if the failing cases are any String but 3 specific Strings : it makes millions of possibilities.
In your case I think that the best way to make your code more robust is using a bounded type as an enum. You could so define a enum that contains 3 values and provide a enum constructor with the String actually passed as a parameter.
It could look like :
public boolean doSomething(MyEnum param1Enum, String param2){
...
String param1 = param1Enum.getString();
}

Related

How to remove java method pararmeters when certain condition is met

I'm trying to find a way to remove a method parameter when a certain condition is met. If the condition is met - then the parameter should be taken away from the method - but if the condition is not met - the parameter should be added back again to that method. Is there any way to do this in java - I know overloaded methods can do this - but how can a method remove its parameters and add them back again is my question.
if(condition == true) {
//remove the parameter from the method because it is not needed
} else {
//add the parameter back again to the method so the code below can use it
}
/*
code which uses the parameter again...
*/
Thank you so much for helping - hope this was not too confusing
Java doesn't support changing method signatures during Runtime. You could instead just overload the same method, with 2 signatures like so:
public void method(int param1, int param2, int optional) {}
public void method(int param1, int param2) {
method(param1, param2, 'value, that is optional, but not necessary currently');
}
The changing of Signatures is not possible, because it would break everything, that accesses the method using its originial signature.

JUnit 5, how to get parameterized test parameter from BeforeEach callback?

I have the following set of methods in different classes:
#ParameterizedTest
#MethodSource("com.myapp.AppleProvider#getApplesDependingOnConditions")
public void testSomething(Apple apple) {
SomeContainer.getInstance().setApple(apple)
// ...
}
The problem is that I cannot avoid copy/pase of the following
name argument for each test call
The very first line of each test - SomeContainer.getInstance().setApple(apple)
I tried to use extension points - BeforeTestExecutionCallback and BeforeEachCallback, but they don't seem to have ability to get parameter with which they are being called.
According to https://github.com/junit-team/junit5/issues/1139 and https://github.com/junit-team/junit5/issues/944 it's not possible to access argument passed to test from extension points yet and parameterized tests don't work for BeforeEach callbacks.
So I'm basically looking for any workaround so that my test could look like:
#MyAwesomeTest
public void testSomething() {
// ...
}
Where #MyAwesomeTest encapsulates two annotations above.
What I've already found:
In extension points the following data is available: displayname, method or tags. If I pass argument into the each test method (though it's very undesirable) looks like I can rely on displayname since it'll reflect argument passed to the method call for a particular parameter.
I'm trying to find out whether there're any other ways without need to add argument into each method.
I think you could cheat to get most of the way there:
public static Stream<String> apples() {
return com.myapp.AppleProvider
.getApplesDependingOnConditions()
.stream()
.peek(apple -> SomeContainer.getInstance().setApple(apple))
.map(apple -> { /* convert to name string */ })
}
#ParameterizedTest
#MethodSource("apples")
public void testSomething(String name) {
// ...
}

Unit-test wrapper methods when base method is private [duplicate]

This question already has answers here:
How do I test a class that has private methods, fields or inner classes?
(58 answers)
Closed 6 years ago.
I read this answer about unit-test a wrapper method. In following code:
public static Object methodA(Object arg) {
if (arg == null) {
return null;
} else {
return methodB();
}
}
It looks reasonable that I don't need to test all functionality in methodB(), just test 2 cases where arg is null and not because methodB() should be tested already.
However, if methodB() is private method, I should test all functionality that methodB() will provide because according to another answer, private methods are implementation details.
The problem is, if I have 2 methods methodA1() and methodA2() and they all call methodB() like this:
public static MyObject methodA1(int x) {
MyObject obj = new MyObject();
obj.setX(x);
return methodB(obj);
}
public static MyObject methodA2(int y) {
MyObject obj = new MyObject();
obj.setY(y);
return methodB(obj);
}
private static MyObject methodB(MyObject obj) {
// doSomething with obj
return obj;
}
Should I test methodA1() and methodA2() separately? Or I can just test the private method methodB() because methodA1() and methodA2() are just wrapper methods of methodB(), so if methodB() is correctly tested, I won't need to test methodA1() and methodA2() at all.
EDIT:
I wrote separate tests for public methods at first. But the problem is, if there are many variations of the methodA, and some of the functionalities / requirements are shared in some of them, then the code of the test cases will be duplicated. That's why I wonder if I should test private method methodB().
The real problem I met is I have requirement to add a record in database, and there are many different APIs I should provide. For example, I should provide:
MyObject addMale(String name, String job); // fill sex with "Male"
MyObject addStudent(String name, String sex); // fill job with "Student"
And all of them checks the parameter is valid or not, fill the field that is not specified and call the private method to actually insert the record into the database, which is so called methodB().
There are many APIs like this, so if I can only test methodB() with all fields situation, maybe I can reduce the duplication of the test cases, but is that a good practice to do the unit tests like this?
EDIT2:
I know I can test private methods because I used reflection in my other test cases, and I know it can invoke private methods, too. But my question is about in this situation, testing private methods is a proper solution or not.
This is actually a question I've wondered about for awhile, and while it's not necessarily correct, I'll share my opinion.
The main problem is that private methods are hard to test. I did some Googling, and there some tools and techniques that let you access private methods (reflection is the main one I encountered), but they seemed a little convoluted.
But the reason you wrote a private method is because there is another method, a public method, that calls it. So while you can't directly test the private method, you can check its functionality by testing the public method which calls it.
If I were you, I would extensively test methodA1() and methodA2(), ensuring that all the functionality of methodB() is tested by the tests you run on the public methods.
You've received a few opinions why you should write unit tests for methodA1() and methodA2(); you've pushed back on them. You asked the question here; you are clearly looking for some justification for not writing complete unit test for them. Let's see if we can give you the answer you want. ;-)
From what you've added in your edit, it looks like you have a variation on a builder pattern. Eg)
MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
How would we test the builder?
Since the builder has 4 attributes, which could be set in any order, there would be 4! = 24 different orderings. A complete test suite would have to include:
#Test public void testXYZW() { ... }
#Test public void testXYWZ() { ... }
// ... 21 more permutations ...
#Test public void testWZYX() { ... }
But is that all? No! Some of those attributes could have default values, so we would have to test those patterns as well. Total orderings is now P(4,4)+P(4,3)+P(4,2)+P(4,1)+P(4,0) = 24+24+12+4+1 = 85 unit test.
#Test public void testXWY() { ... }
#Test public void testWY() { ... }
#Test public void testZ() { ... }
// ... 61 more permutations ordering
And this only tests each permutation of X, Y, Z, W attributes with one test value per attribute per test. It is clearly unwieldy to write an exhaustive set of tests for every possible combination and permutation.
The designer of the builder class would understand that the permutation of the attribute settings does not affect the resulting construction; writing tests for permutations of the order does not actually increase the test coverage. Tests for omitted attributes are useful, as they test the default values. Testing of different combinations of the omitted attributes again would not increase the test coverage. So, after careful thought, only two tests might be required:
#Test
public void testXYZW() {
MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
assertThat(o.wasBuiltProperly());
}
#Test void testDefaults() {
MyObject o = new Builder().build();
assertThat(o.wasBuiltProperlyFromDefaults());
}
If proper, complete testing of methodB() is being done, then you could safely get away with testing only the validation of inputs in methodA1() and methodA2().
#Test void testMethodA1Professor() {
MyObject o = methodA1("professor");
assertThat(o.wasBuiltProperlyWithProfessor());
}
#Test void testMethodA1WithNull() {
MyObject o = methodA1(null);
assertThat(o.wasBuiltProperlyWithNull());
}
Oftentimes, when a private method is used by multiple methods inside a class, there's a distinct concept lurking behind it. It may deserve to have its own class.
it should not be used outside of the class
There are a few ways you could extract methodB to its own class and not make it available as part of your public API :
Nest it inside the class that uses it and give it a restricted scope
Put it in another module at a lower level. Make that module available from your API but not from the clients.

Mocking with functionality

I am very new to Mockito, please let me know if I'm on the right track. I'm trying to mock method functionality using Mockito.
sscce
public SUTclass {
private final DependencyInjectedObj dep; // already successfully mocked
private int statefulInteger;
private int otherInteger;
public int doSomething() {
return otherInteger + dep.doMath(statefulInteger);
}
}
Right now, dep is mocked... but dep.doMath always returns 0. In production, dep is stateful - no way to avoid it. In production, a different thread updates its state in real time. dep.doMath does some funky calculations depending on the state right now. You could imagine that production functionality might look at a thermometer and do something with it's temerature, and doSomething gives a realtime status based on that temperature.
In my test, though, I'd like to have dep.doMath have this functionality (which is a sufficient approximation for a unit test):
public int doMath(int input) {
return SOMECONSTANT * input;
}
I suppose I could create a Mock implementation of DependencyInjectedObj and use that, but that seems to defeat the purpose of using Mockito and the when syntax. What should I do?
In this case, what you want is doAnswer(). It allows you to execute arbitrary code when a mock invocation is called:
doAnswer(new Answer<Integer>() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
int i = (int)args[0];
return i * CONSTANT;
}
}).when(dep.doMath(any(Integer.class));
I do consider doAnswer a bit evil, though. Generally thenReturn(CONSTANT) is sufficient for most unit tests. If you're going to verify the result of this method call, then you're testing the wrong class -- the point of mocking your dependencies is you don't much care about their operation.

Mockito: InvalidUseOfMatchersException

I have a command line tool that performs a DNS check. If the DNS check succeeds, the command proceeds with further tasks. I am trying to write unit tests for this using Mockito. Here's my code:
public class Command() {
// ....
void runCommand() {
// ..
dnsCheck(hostname, new InetAddressFactory());
// ..
// do other stuff after dnsCheck
}
void dnsCheck(String hostname, InetAddressFactory factory) {
// calls to verify hostname
}
}
I am using InetAddressFactory to mock a static implementation of the InetAddress class. Here's the code for the factory:
public class InetAddressFactory {
public InetAddress getByName(String host) throws UnknownHostException {
return InetAddress.getByName(host);
}
}
Here's my unit test case:
#RunWith(MockitoJUnitRunner.class)
public class CmdTest {
// many functional tests for dnsCheck
// here's the piece of code that is failing
// in this test I want to test the rest of the code (i.e. after dnsCheck)
#Test
void testPostDnsCheck() {
final Cmd cmd = spy(new Cmd());
// this line does not work, and it throws the exception below:
// tried using (InetAddressFactory) anyObject()
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class));
cmd.runCommand();
}
}
Exception on running testPostDnsCheck() test:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
Any input on how to solve this?
The error message outlines the solution. The line
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class))
uses one raw value and one matcher, when it's required to use either all raw values or all matchers. A correct version might read
doNothing().when(cmd).dnsCheck(eq(HOST), any(InetAddressFactory.class))
I had the same problem for a long time now, I often needed to mix Matchers and values and I never managed to do that with Mockito.... until recently !
I put the solution here hoping it will help someone even if this post is quite old.
It is clearly not possible to use Matchers AND values together in Mockito, but what if there was a Matcher accepting to compare a variable ? That would solve the problem... and in fact there is : eq
when(recommendedAccessor.searchRecommendedHolidaysProduct(eq(metas), any(List.class), any(HotelsBoardBasisType.class), any(Config.class)))
.thenReturn(recommendedResults);
In this example 'metas' is an existing list of values
It might help some one in the future: Mockito doesn't support mocking of 'final' methods (right now). It gave me the same InvalidUseOfMatchersException.
The solution for me was to put the part of the method that didn't have to be 'final' in a separate, accessible and overridable method.
Review the Mockito API for your use case.
May be helpful for somebody. Mocked method must be of mocked class, created with mock(MyService.class)
For my case, the exception was raised because I tried to mock a package-access method. When I changed the method access level from package to protected the exception went away. E.g. inside below Java class,
public class Foo {
String getName(String id) {
return mMap.get(id);
}
}
the method String getName(String id) has to be AT LEAST protected level so that the mocking mechanism (sub-classing) can work.
Inspite of using all the matchers, I was getting the same issue:
"org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
1 matchers expected, 3 recorded:"
It took me little while to figure this out that the method I was trying to mock was a static method of a class(say Xyz.class) which contains only static method and I forgot to write following line:
PowerMockito.mockStatic(Xyz.class);
May be it will help others as it may also be the cause of the issue.
Another option is to use a captor: https://www.baeldung.com/mockito-argumentcaptor
// assume deliver takes two values
#Captor
ArgumentCaptor<String> address; // declare before function call.
Mockito.verify(platform).deliver(address.capture(), any());
String value = address.getValue();
assertEquals(address == "some#thing.com");
Captors are especially useful if say one member of the object you want to capture could be a random ID and another is something you can validate against.
Do not use Mockito.anyXXXX(). Directly pass the value to the method parameter of same type.
Example:
A expected = new A(10);
String firstId = "10w";
String secondId = "20s";
String product = "Test";
String type = "type2";
Mockito.when(service.getTestData(firstId, secondId, product,type)).thenReturn(expected);
public class A{
int a ;
public A(int a) {
this.a = a;
}
}

Categories

Resources