How to test a toString() method? - java

If I have something like this:
public class Set {
private ArrayList<String> testList;
private String testString;
public Set() {
}
public void add(String testString) {
testList.add(testString);
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(testString).append(System.getProperty("line.separator"));
return sb.toString();
}
}
How can I test this in a main method?
This is what I've tried so far...
Set test = new Set();
test.add("blah");
test.add("blahhh");
System.out.println(blah.toString());
Am I doing this correctly? Taking my first CS course in High School and we're supposed to make a class that implements a toString() method.

you creacted the object test of the class Set just write now just:
System.out.println(test);
will give you the result you want since it will use the toString method
and your testString is not set so the toString will return null

You can test your toString this way, but for this purpose you should use Unit Tests (see junit).
For testing your Class you should try it with different types of input, to see, what happens, if someone enteres something unexpected.
And you have errors in your Code:
Set test = new Set();
test.add("blah");
test.add("blahhh");
System.out.println(blah.toString());
There is no blah variable:
System.out.println(test.toString());
or just:
System.out.println(test);
For learning purposes you should do something more usefull in your toString. You could try to create a Class bank account with balance, owner data (name, address, ...) and creating in the toString an interesting output.

You are asking about testing; then dont go for print statements.
Turn to a unit test environment, like JUnit; and write real tests:
#Test
public testToStringWithTwoEntries() {
Set underTest = new Set();
underTest.add(...
assertThat(underTest.toString(), is("blah, blahhh"));
}
for example. Notes:
assertThat() is simply one of the most powerful of the various different assert methods; and it is easy to use; one just has to understand that it requires Hamcrest matchers to work (that is where the is() call is coming from)
you named your class "Set" ... bad idea. There is already a well-known interface java.util.Set. You never want to re-use such names.

A very good library for testing toString on model classes: https://github.com/jparams/to-string-verifier
Sample:
#Test
public void myTest()
{
ToStringVerifier.forClass(Set.class).verify();
}

Related

Test an overridden method of an inner class with JUnit and Mockito

I have a method in a class I need to test. The method uses an external class that I need to mock, so the external class doesn't get tested or executes its dependencies. The special challenge is: one method of the external class gets overridden. Method looks like this:
public void fetchLocalData(final String source, final ObservableEmitter<String> destination) {
final List<String> options = Arrays.asList("recursive","allFiles","includeDir");
// This class comes from a package
final DirScan dirscan = new DirScan(source, options) {
#Override
protected Action getResult(final String result) {
destination.onNext(result);
return Action.Continue;
}
};
dirscan.scan();
destination.onComplete();
}
I tried:
DirScan scanner = mock(DirScan.class);
when(scanner.scan()).thenReturn("one").thenReturn("two");
That didn't work. What do I miss? How would I need to refactor to make this testable?
If you want to replace the dirscan with a mock (or a spy) you'll need to refactor your class that it's a dependency or parameter. Alternatively you could use PowerMockito's whenNew functionality.
Lets assume you change your class and instead of the String source you provide the DirScan object as a parameter. You would need to have some kind of creation method for dirscan elsewhere (might be a static method).
final List<String> options = Arrays.asList("recursive","allFiles","includeDir");
public DirScan createDirScan(String source) {
// This class comes from a package
final DirScan dirscan = new DirScan(source, options) {
#Override
protected Action getResult(final String result) {
destination.onNext(result);
return Action.Continue;
}
};
return dirscan;
}
public void fetchLocalData(final DirScan dirscan, final ObservableEmitter<String> destination) {
dirscan.scan();
destination.onComplete();
}
Juding from your question you seem to want to test the interaction with the destination object, so you do not want to mock the dirscan object (because if you do there won't be any interaction). You might want to use a spy and only replace the getResult method.
In your test now you could then simply pass a spy for the dirscan object and
define the behaviour of it with thenAnswer.
final ObservableEmitter<String> destination = ...
DirScan dirscan = Mockito.spy(createDirScan(source, destination));
Mockito.when(dirscan.getResult(Mockito.any(String.class))).thenAnswer((Answer<Action>) invocation -> {
String result = invocation.getArgument(0);
destination.onNext(result);
return Action.Continue;
});
classUnderTest.fetchLocalData(dirscan, destination);
At this point you might notice that its probably better to not use a spy and just use the real DirScan object. Using the spy to do what you intend to do with the overriden method looks like overkill to me.
The real object has to work for this test to be of value, so you might as well test the real thing.

How to pass a method as an argument to a different method?

I have a method let's say in ClassA. I want to pass a method from ClassB as an argument to that method in ClassA. In this case I want to pass the getCode method from ClassB. I don't have any instance of ClassB and I'd like to achieve this without having to create one.
I've tried using simple method reference, but it does not work this way.
I don't want to make getCode a static method either.
public class ClassA {
public void validate() {
Validation validation = new Validation(ClassB::getCode, code);
//...
}
}
My final goal is to have a RequestValidator class to which add validations, each validation will be created with a specific method and a string in its constructor, in this case getCode from classB and code. Please note I only want one instance of RequestValidator. Something like this:
RequestValidator validator = new RequestValidator<>()
.addValidation(new Validation(ClassB::getCode, code))
.addValidation(new Validation(ClassB::getName, name));
getCode needs to be a static function, and the syntax would be ClassB.getCode. You would need ClassB to be imported into ClassA.
See:
Calling static method from another java class
Your use of a method reference will work just fine as long as you define the method arguments properly. You haven't given a lot of information, so I'm going to make some assumptions here. Please correct me if this isn't what you had in mind:
public class B {
public static String getCode() {
return "foobar"; // Replace with your own functionality
}
}
public class Validation {
Validation(Supplier<String> supplier, String code) {
String suppliedCode = supplier.get();
// Do your validation logic
}
}
public static void validate() {
Validation validation = new Validation(ClassB::getCode, code);
}
But this frankly feels like overkill. Why can't you just make your Validation constructor take two String arguments (or whatever types you happen to be using), and then do this?
public static void validate() {
Validation validation = new Validation(ClassB.getCode(), code);
}
Do you have a legitimate need to pass in a method reference instead of simply passing in the return value from the method call?

How to mock method with variable parameters eg concatenate(String... messages)

How to mock method with variable parameters concatenate(String... messages)
If I pass parameters as
String[] messages = {"abc"};
Helper helper = mock(Helper.class);
doReturn(someStr).when(helper).concatenate(messages);
It won't work.
I honestly don't see the problem. Let's try it ...
Let's assume we have this class...
public class Helper {
public String concatenate(String...strings) {
// ...some concat logic, not important
}
}
...and now we want to mock it...
#Test
public void testSomething() {
Helper helper = Mockito.mock(Helper.class);
Mockito.doReturn("blablub").when(helper).concat(Mockito.anyVararg());
Assertions.assertThat(helper.concat("bla", "bli")).isEqualTo("blablub");
}
And yes, this works. We give it "bla" and "bli", but because we told the mock to return "blablub" in any case, we get that as result. So mocking any vararg is easy enough... We can of course also only check part of the whole vararg, for example...
Mockito.doReturn("blablub").when(helper).concat(Mockito.anyString(), Mockito.eq("blub"), Mockito.anyVararg());
Assertions.assertThat(helper.concat("bli", "blub", "bla", "blu", "blo")).isEqualTo("blablub");
...which will return "blablub" as long as then 2nd argument is "blub", no matter what the others are.
Better to use reflection method to initiate string value
FieldUtils.writeField(testClass, "stringVariableName", "value", true);

Test a method without initialize the class

I'm very new to unit testing, I'm wondering if there is a way to test a method without initializing the class. The reason I'm asking is because there are lot of object passing in the constructor meaning a lot of mocking stubbing while from a thorough check methodToTest seems not to use any object attribute. It's not my code otherwise the method could be converted to static.
class ExampleClass {
public ExampleClass(FirstClass fc, SecondClass sc, ThirdClass tc) {}
public void methodToTest(FourthClass foc) {}
}
You have some options here:
Make the method static so you don't need a reference to an actual object. This will only work if the method does not need any state of ExampleClass (i.e. everything it needs is passed in the method arguments).
Extract this method to another class (perhaps using the method object pattern) that's easier to test on its own. This refactoring is called replace method with method object.
Usually, having to many parameters in constructors is a hint on bad conception. You'd better rethink you Objects and classes to reduce argument to give to the constructor.
If you don't want to, you can still use some kind of a "TestUtil" wich instantiate class for you.
Example :
public class MyTestUtils {
public createValidFirstClass() {
return new FirstClass(/* some arguments here */);
}
public createValidSecondClass() {
return new SecondClass(/* Some arguments here */);
}
public createValidThridClass() {
return new ThridClass(/* Some arguments here */);
}
public createValidExampleClass() {
return new ExampleClass(createValidFirstClass(), createValidSecondClass(), createValidThridClass());
}
}
This class MUST be in your test packages and not in your project, and should not be used outside of the tests, it would be a really bad practice here, use Factory or Builder for your real projects.
Anyway, i think that the best solution is to rethink you Classes.
Example :
public class People {
public People(String firstName, String lastName, Date birth, Date death) {
}
}
As you can see this is a pain in the ass to control that all given parameter was correctly formatted and not null.
This number of argument passed to a method can be reduced this way.
public class People {
public People(PeopleNames names, Period period) {
}
}
public class PeopleNames {
public People(String firstName, String lastName) {
}
}
public class PeopleNames {
public People(Date begin, Date end) {
}
}
Ok, it seems I found a way. Since the method is irrelevant to the state of the object, I could mock the object and order the MockRunner to use the real method when it is called. It is named partial mocking. The way of doing it is
ExampleClass = PowerMockito.mock(ExampleClass.class);
when(ExampleClass.methodToTest(foc)).thenCallRealMethod();
As far as I know, you cannot conduct a Test without initializing the class.
The three steps of Test are Arrange,Act and Assert. The class has to be initialized in the arrange part for fetching the required methods in the particular class you are testing.
I don't know what your method does but if it's possible for your application you could just make methodToTest static, which would allow you call it without an instance of the class.
Alternatively, you could avoid too much instantiation by creating one instance in a #BeforeClass method to be used for all tests, but again I don't know what you method does so that might not be desirable.
Use suppressions from PowerMockito.
import org.powermock.api.support.membermodification.MemberModifier;
import org.powermock.api.support.membermodification.MemberMatcher;
suppress(MemberMatcher.constructor(ExampleClass.class))

how to unit test a class which creates new objects

I'm using JUnit and Mockito to test some classes. The class itself creates an object from another class. A list called testList. Here my code:
public class A {
private List<B> bList;
//returns the bList
public List<B> getBList() {
return bList;
}
//checks the status by calling getStatus in class B
public Status getStatus() {
//status is an enum consists of PASSED and FAILED
Status finalStatus = Status.PASSED;
for (B be : this.getTestList()) {
if (be.getStatus() != Status.PASSED) {
finalStatus = Status.FAILED;
break;
}
}
return status;
}
}
public Class B {
private Status status = Status.FAILED;
public getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
}
What would be the best way to test the getStatus and getTestList methods in the class called Test.
Thank you very much....
I looked at your ClassA and I wondered how bList ever gets set to anything. Right now, there's no way for it to be anything other than null, which means that getStatus will throw a null pointer exception every time.
Your problem is that you are thinking about how to test methods instead of thinking about how to test behaviour. One reason why this is a problem is that your class has to fit in with the rest of your application in a certain way. To be sure that it does that, it needs certain behaviour, not certain details within each method. So the only meaningful test is one that checks the behaviour.
Perhaps more insidious is the fact that testing individual methods makes you focus on the code that you have in fact written. If you are looking at your code while you write your test, then your test becomes a self-fulfilling prophecy. You may have missed a whole set of behaviour that your class is required to provide; but if you only test the behaviour that your class does provide, you'll never know.
So, back to the problem in hand. I see four, maybe five behaviours that your class might be expected to fulfil. Maybe there are more - it's hard to tell if you only show us the code, and not the specification. You should write a test for each one. I strongly believe that the name of each test should describe the behaviour, rather than reflecting the name of the methods that the test uses. In this case, I might choose names like this.
public void statusIsPassedWhenEveryTestPassed()
public void statusIsFailedWhenEveryTestFailed()
public void statusIsFailedWhenSomeTestsPassedSomeFailed()
public void statusIsPassedWhenNoTests()
public void statusIsPassedWhenTestsNotSet() // this one currently fails
Within each test, I would create an object of ClassA, then do whatever has to be done to set the bList within the object. Lastly, I would call getStatus and assert that the return value is what I want. But the important point is that each test (except the last one) uses more than one method of ClassA, so these are not tests of an individual method.
You can provide setters (or constructor injection) for the objects in question as protected and then extend the class inside your test case to mock the objects or you can try using something like powermock. You would still need to provide a way to set those objects in question.
I guess it depends on how you can populate testList in a unit test. If you have, say, a setter, then you would not need any mocking frameworks
class TestTest {
Test test = new Test();
#Test void should_return_failed_if_a_single_test_failed() {
givenTestListWithOneFailedTest();
assertThat(test.getStatus(), is(Status.FAILED))
}
void givenTestListWithOneFailedTest() {
test.setTestList(createSomeTestListWithOnlyOneFailedTest());
}
#Test void should_return_passed_if_all_tests_passed() {
// ...
}
}

Categories

Resources