I am trying to improve my knowledge about testing I'm trying to achieve running the same JUnit test class with different objects derived from the same interface.
so we can assume the following:
interface Base {
void sort();
}
class A implements Base {
#Override
public void sort() {
//sort naively
}
}
class B implements Base {
#Override
public void sort() {
//sort using another better approach
}
}
class C implements Base {
#Override
public void sort() {
//sort using optimized approach
}
}
class Test {
#Test
void test1() {
Base obj = new A();
obj.sort();
obj.otherStuff();
}
}
class SecondTest {
//trying to avoid making multiple test classes that has only one line in difference
#Test
void test1() {
var obj = new B();
obj.sort();
obj.otherStuff();
}
So my question is how to run the test class with the objects from A,B,C without falling into the trap of duplicate code and redundancy?
Please note that I wrote this example just to illustrate my point, and the sort() doStuff() methods are just placeholders but when you have over ~70 line of code duplication in each test class it starts to look ugly and redundant.
*I have looked at #beforeEach, #Before, #After and I don't think I see a way where those might help me.
You can write a parameterized test with a MethodSource.
#ParameterizedTest
#MethodSource("bases")
void test1(Base obj) {
obj.sort();
obj.otherStuff();
}
static Stream<String> bases() {
return Stream.of(new A(), new B(), new C());
}
A way to fix it is the following, you create a method within your test class that takes as input the Base obj and contains all the duplicate lines. What you'll do then is to initialize the obj in different tests, then pass it to the method.
Here is a code that would do the job:
class Test {
#Test
void test1() {
Base obj = new A();
wrapperMethod(obj);
}
#Test
void test2() {
var obj = new B();
wrapperMethod(obj);
}
public static void wrapperMethod(Base obj){
obj.sort();
obj.otherStuff();
}
}
As a rule of thumb, testing can be much like normal programming where redundancy is avoided with methods to guarantee reusability.
Cheers,
D
First of all you have to fix your understanding of what UnitTesting is about.
UnitTesting is not about code (coverage).
UnitTesing is about verifying desired public behavior where "public behavior means return values and/or communication with dependencies.
Each test method should verify a single atomic assumption of the tested units desired behavior.
From this point of view it does not make sense to pass a bunch of objects sharing the same interface trough the same test method since these different interface implementations exist to implements the interfaces methods with their own unique behavior. In turn the assumption how the objects behave differ uniquely.
If all the objects where expected to behave identically (which is the only assumption a single test method could verify) there where no different objects (i.e. implementations) in the first place.
I have this original code:
public SomeClass(int parameter) {
this.someProperty = parameter;
this.apiObject = new SomeApiClass(someProperty);
for(i=0; i < 2; i++)
apiObject.setApiProperty(i, "Hello World");
}
The code works perfectly fine. But the problem arises when I try to test the same.
#Mock
private SomeApiClass someApiClass;
private SomeClass someClass;
#Before
public void setUp() throws Exception {
someClass = new SomeClass(3);
}
#Test
public void shouldCreateSomeClass() {
verify(someApiClass, times(2)). setApiProperty(anyInt(),anyString());
}
I understand why this test wouldn't pass. This would work if I change the constructor to this:
public SomeClass(int parameter, SomeApiClass someApiClass) {
...
}
How do I test the original code if I do not want to inject SomeApiClass to the constructor and also can't afford to provide any getters in it.
PS: Please ignore typos in the code. Typed it on the fly.
It's good to think about testability when you design your class and also to differentiate parameters and dependencies.
Dependencies are objects that the class will rely on to get its work done. They generally don't change throughout the lifecycle of the dependee object.
Parameters are more localized than dependencies. They are expected to change in between calls to the methods of the object.
In the original code, it looks like the work done in the constructor for SomeClass should really go inside a method:
public class SomeClass {
public void doWork(int parameter) {
//
}
}
Inside the method, if you are only interested in instantiating SomeApiObject with the parameter, then why not follow the Law of Demeter and pass in directly SomeApiObject as a parameter:
public void doWork(SomeApiObject someApiObject) {
//
}
Then the consumer does the work:
someClass.doWork(new SomeApiObject(3));
and it can be tested by passing in a mocked SomeApiObject as a parameter:
//act
someClass.doWork(mockedSomeApiObject);
//assert
verify(mockedSomeApiObject).someVerification();
However, if you want a combination of parameters and dependencies you can use a Factory as a dependency:
public class SomeClass {
private final SomeApiObjectFactory someApiObjectFactory;
public SomeClass(SomeApiObjectFactory someApiObjectFactory) {
this.someApiObjectFactory = someApiObjectFactory;
}
public void doWork(int parameter) {
SomeApiObject someApiObject = someApiObjectFactory.create(parameter);
//etc
}
Then you can now test the class since you have a way to supply mocks on which behaviour can be verified:
SomeApiObject mockSomeApiObject = Mockito.mock(SomeApiObject.class);
when(mockSomeApiObjectFactory.create(anyInt()).thenReturn(mockApiObject);
Aside from all of that there are ways of using Powermockito to test your original class as it is without alteration but these are not ideal and it is best to refactor if possible so you can use plain Mockito to test. This will give you good OO habits. Good luck!
I am new to TDD and I am confused!
My first question is how would a test lead to declaration of variables with a name that you want?
For instance if I had some code in my test say
public class someTest {
#Test
public void test(){
new someMethod(1,0);
}
}
So, is there a way to name the variables in the test?
My second question is if I wanted the method to do a System.out.print("Some error") because of one of the variables value and then return what would the test need to contain?
I am completely lost. So any help is appreciated.
Forget about TDD for a moment. How would you think about testing if you started with an interface or class first? Here's what I'd do: Start with my class Foo.
public class Foo {
private String message;
public Foo(String m) { this.message = m; }
public String getMessage() { return this.message; }
public static int add(int x, int y) { return x*y; }
}
Then I'd write a JUnit test for it:
public class FooTest {
#Test
public void testConstructor() {
String expected = "Hello";
Foo f = new Foo(expected);
Assert.assertEquals(expected, f.getMessage());
}
#Test
public void testAdd() {
int expected = 5;
Assert.assertEquals(expected, Foo.add(2, 3));
}
}
I'd run this test and immediately figure out that I had a problem with that add implementation.
So what does TDD do? They take things to the extreme: write the test first, then write the class. You try to compile the test and it fails because you didn't write the class. Once you have a class implementation, you maintain a tight loop of code-test for every method, maintaining 100% passing and good coverage including happy path, error conditions, and edge cases.
TDD doesn't mean you have no idea about the class you're going to write and test. You should have some idea of the API you need before you start.
Personally, I think demanding that you write the test before the class is silly. Sketch out the class, just don't go too far before you test it. Write a method, test it, write another.
By the way: If you write a JUnit test without an Assert in it you're doing it wrong. Don't write to System.out. The pass or fail judgment should not depend on your visual inspection; it should be asserted and determined automatically.
You shouldn't care about particular variables being created. If the tests you write correctly describe the behaviour you desire, and your implementation works as you want it, why do you care what variables does it have inside? Eventually, you will be forced to create some variables to satisfy one of subsequent tests. Its name shouldn't be tested - this is implementation detail, on which tests shouldn't rely.
I might be asking something completely obvious. I do not have much experience in writing unit tests, and the following question came up which got me thinking.
Say, you have a class and this class has methods you want to test. But can you test a single method at once? I think not. In order to test the method, you need to invoke one or more other methods. For example:
class MyClass {
int x;
void foo() { x = 4; }
boolean bar() { x = 3; }
boolean check() { return x == 4; }
}
In order to test foo and bar, I need to use check() and on the other hand, in order to test check I need to use either foo() or bar().
Say, I have to following test case:
class MyClassTest {
#Test
void testFoo() {
MyClass obj = new MyClass();
obj.foo();
assert obj.check();
}
}
Now let's assume, my colleague changes the check() method:
boolean check() { return x == 5; }
Of course, the testFoo() will fail, and one might think that there is a problem with the foo method.
So this looks like a chicken-egg situation. How do people usually resolve this?
It probably doesn't make much sense to test methods independently here because the state of the class can change according to the sequence of methods called. In this case I'd make sure the behavior - or state transitions - work as expected. Please refer to the following three tests which properly specify the behavior of the class:
class WhenFooWasCalled {
#Test
public void ThenCheckShouldReturnTrue {
MyClass sut = new MyClass();
sut.foo();
assertTrue(sut.check());
}
}
class WhenBarWasCalled {
#Test
public void ThenCheckShouldReturnFalse {
MyClass sut = new MyClass();
sut.bar();
assertFalse(sut.check());
}
}
class WhenNothingWasCalled {
#Test
public void ThenCheckShouldReturnFalse {
MyClass sut = new MyClass();
assertFalse(sut.check());
}
}
Updated: I added a third test case: How does the check() behave if neither foo() nor bar() were called.
You don't write tests for individual methods - you write tests for individual requirements. In this case your class seems to have two requirements:
"check must return true when foo was called last"
"check must return false when bar was called last"
So you would write two unit-tests, one for each requirement to verify that the class fulfills it correctly (you might want to formulate a third requirement: what check is supposed to do when neither was called). When your colleague made the change above, he broke neither the foo method, not the check method. What he broke was the first requirement. Now he has to change the class somehow so that it fulfills it again. How he accomplishes this (change foo, change checkor both) doesn't matter.
This is common with a class with internal mutable state. I think your question reduces to your unit tests behaving properly after a given sequence of state manipulations.
public class A {
public void method(boolean b){
if (b == true)
method1();
else
method2();
}
private void method1() {}
private void method2() {}
}
public class TestA {
#Test
public void testMethod() {
A a = mock(A.class);
a.method(true);
//how to test like verify(a).method1();
}
}
How to test private method is called or not, and how to test private method using mockito?
Not possible through mockito. From their wiki
Why Mockito doesn't mock private methods?
Firstly, we are not dogmatic about mocking private methods. We just
don't care about private methods because from the standpoint of
testing private methods don't exist. Here are a couple of reasons
Mockito doesn't mock private methods:
It requires hacking of classloaders that is never bullet proof and it
changes the api (you must use custom test runner, annotate the class,
etc.).
It is very easy to work around - just change the visibility of method
from private to package-protected (or protected).
It requires me to spend time implementing & maintaining it. And it
does not make sense given point #2 and a fact that it is already
implemented in different tool (powermock).
Finally... Mocking private methods is a hint that there is something
wrong with OO understanding. In OO you want objects (or roles) to
collaborate, not methods. Forget about pascal & procedural code. Think
in objects.
You can't do that with Mockito but you can use Powermock to extend Mockito and mock private methods. Powermock supports Mockito. Here's an example.
Here is a small example how to do it with powermock
public class Hello {
private Hello obj;
private Integer method1(Long id) {
return id + 10;
}
}
To test method1 use code:
Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));
To set private object obj use this:
Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);
While Mockito doesn't provide that capability, you can achieve the same result using Mockito + the JUnit ReflectionUtils class or the Spring ReflectionTestUtils class. Please see an example below taken from here explaining how to invoke a private method:
ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");
Complete examples with ReflectionTestUtils and Mockito can be found in the book Mockito for Spring.
Official documentation Spring Testing
By using reflection, private methods can be called from test classes.
In this case,
//test method will be like this ...
public class TestA {
#Test
public void testMethod() {
A a= new A();
Method privateMethod = A.class.getDeclaredMethod("method1", null);
privateMethod.setAccessible(true);
// invoke the private method for test
privateMethod.invoke(A, null);
}
}
If the private method calls any other private method, then we need to spy the object and stub the another method.The test class will be like ...
//test method will be like this ...
public class TestA {
#Test
public void testMethod() {
A a= new A();
A spyA = spy(a);
Method privateMethod = A.class.getDeclaredMethod("method1", null);
privateMethod.setAccessible(true);
doReturn("Test").when(spyA, "method2"); // if private method2 is returning string data
// invoke the private method for test
privateMethod.invoke(spyA , null);
}
}
**The approach is to combine reflection and spying the object.
**method1 and **method2 are private methods and method1 calls method2.
Think about this in terms of behaviour, not in terms of what methods there are. The method called method has a particular behaviour if b is true. It has different behaviour if b is false. This means you should write two different tests for method; one for each case. So instead of having three method-oriented tests (one for method, one for method1, one for method2, you have two behaviour-oriented tests.
Related to this (I suggested this in another SO thread recently, and got called a four-letter word as a result, so feel free to take this with a grain of salt); I find it helpful to choose test names that reflect the behaviour that I'm testing, rather than the name of the method. So don't call your tests testMethod(), testMethod1(), testMethod2() and so forth. I like names like calculatedPriceIsBasePricePlusTax() or taxIsExcludedWhenExcludeIsTrue() that indicate what behaviour I'm testing; then within each test method, test only the indicated behaviour. Most such behaviours will involve just one call to a public method, but may involve many calls to private methods.
Hope this helps.
I was able to test a private method inside using mockito using reflection.
Here is the example, tried to name it such that it makes sense
//Service containing the mock method is injected with mockObjects
#InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;
//Using reflection to change accessibility of the private method
Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
//making private method accessible
m.setAccessible(true);
assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));
You're not suppose to test private methods. Only non-private methods needs to be tested as these should call the private methods anyway. If you "want" to test private methods, it may indicate that you need to rethink your design:
Am I using proper dependency injection?
Do I possibly needs to move the private methods into a separate class and rather test that?
Must these methods be private? ...can't they be default or protected rather?
In the above instance, the two methods that are called "randomly" may actually need to be placed in a class of their own, tested and then injected into the class above.
There is actually a way to test methods from a private member with Mockito. Let's say you have a class like this:
public class A {
private SomeOtherClass someOtherClass;
A() {
someOtherClass = new SomeOtherClass();
}
public void method(boolean b){
if (b == true)
someOtherClass.method1();
else
someOtherClass.method2();
}
}
public class SomeOtherClass {
public void method1() {}
public void method2() {}
}
If you want to test a.method will invoke a method from SomeOtherClass, you can write something like below.
#Test
public void testPrivateMemberMethodCalled() {
A a = new A();
SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
a.method( true );
Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}
ReflectionTestUtils.setField(); will stub the private member with something you can spy on.
I don't really understand your need to test the private method. The root problem is that your public method has void as return type, and hence you are not able to test your public method. Hence you are forced to test your private method. Is my guess correct??
A few possible solutions (AFAIK):
Mocking your private methods, but still you won't be "actually" testing your methods.
Verify the state of object used in the method. MOSTLY methods either do some processing of the input values and return an output, or change the state of the objects. Testing the objects for the desired state can also be employed.
public class A{
SomeClass classObj = null;
public void publicMethod(){
privateMethod();
}
private void privateMethod(){
classObj = new SomeClass();
}
}
[Here you can test for the private method, by checking the state change of the classObj from null to not null.]
Refactor your code a little (Hope this is not a legacy code). My funda of writing a method is that, one should always return something (a int/ a boolean). The returned value MAY or MAY NOT be used by the implementation, but it will SURELY BE used by the test
code.
public class A
{
public int method(boolean b)
{
int nReturn = 0;
if (b == true)
nReturn = method1();
else
nReturn = method2();
}
private int method1() {}
private int method2() {}
}
Put your test in the same package, but a different source folder (src/main/java vs. src/test/java) and make those methods package-private. Imo testability is more important than privacy.
In cases where the private method is not void and the return value is used as a parameter to an external dependency's method, you can mock the dependency and use an ArgumentCaptor to capture the return value.
For example:
ArgumentCaptor<ByteArrayOutputStream> csvOutputCaptor = ArgumentCaptor.forClass(ByteArrayOutputStream.class);
//Do your thing..
verify(this.awsService).uploadFile(csvOutputCaptor.capture());
....
assertEquals(csvOutputCaptor.getValue().toString(), "blabla");
Building on #aravind-yarram's answer: Not possible through mockito. From their wiki
So what's the OO way of testing private methods? Private methods with complex logic might be a sign that your class is violating the principle of single responsibility and that some of the logic should be moved to a new class.
Indeed, by extracting those private methods to public methods of more granular classes, you can unit test them without breaking the encapsulation of your original class.