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.
Related
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 just started learning JUnit very recently and came across the following problem.
Have a look at the following class
class MyClass {
String a;
public MyClass(String a) {
this.a=a;
String doSomething(String a) {
if( a.isEmpty() )
return "isEmpty";
else
return"isNotEmpty";
}
I want to test the above method for both the conditions. If I proceed with the general structure of writing testcases it will look something like this:
class MyClassTest {
MyClass myClass;
#BeforeEach
void setUp() {
myClass=new MyClass("sampleString");
}
#Test
void doSomethingTest() {
Assertions.equal("isNotEmpty", myClass.doSomething());
}
}
However, for testing the empty string condition I will need another setup method where instead of "sampleString" I pass an empty string.
Following are the approaches I could think of and the questions for each:
Not use setUp at all and instead initialize the class in the individual test method. However, if let's say there are 10 testcases; 5 of which require empty string and rest "sampleString" then this doesn't make sense. Again, we can have a separate method for this repetitive code and call it individually in each testcase but then that defeats the purpose of having a steup method. Lets say I wanted to use two different setup methods, is there a way to do so?
Have a parameterized setup. I don't know if this is possible though. If yes, please share some useful links for this.
Use TestFactory. I tried reading up about this, but couldn't find an example for this specific case. If you have any, please share.
This example has been kept simple for illustrative purposes.
Group the tests with the same setup in an inner class annotated with #Nested. Each nested test class can have its own setup in a local #BeforeEach method.
You can always prepare the non-common data inside your test method. I've always thought it's easier this way, compared to using parameterized tests. You can't mix parameterized and non-parameterized tests in 1 file.
#Test
void doSomething_nullString()
{
myClass = new MyClass(null);
Assert.assertNull(myClass.doSomething());
}
#Test
void doSomething_emptyString()
{
myClass = new MyClass("");
Assert.assertEquals("", myClass.doSomething());
}
#Test
void doSomething_nonEmptyString()
{
myClass = new MyClass("sampleString");
Assert.assertEquals("sampleString", myClass.doSomething());
}
Or, you can always have helper methods inside the test class.
private MyClass createTestObject_nonNullString() {
return new MyClass("nonNullString");
}
private MyClass createTestObject_nullString() {
return new MyClass(null);
}
#Test
public void doSomething_sample() {
MyClass test = createTestObject_nonNullString();
// perform test
}
I would like to mock ALL methods on a class to return one result, instead of mocking each separately, something like:
mock(Foo.class, allMethodsWithAnyArgs).thenReturn('abc');
I'm very new to Java testing so please forgive the dumb question. This giant project has Mockito, PowerMockito, PowerMock, EasyMock, and probably other stuff so I can use anything recommended.
An extended example would be something like this, where I need to test Foo:
public class Foo {
doSomething(){
Bar bar = new bar();
// some code
bar.x(a);
// some code
bar.x(a, b, c);
// some more code
bar.y(...);
// even more code
bar.z(...);
}
}
I need to stub all the bar calls but don't care about the return, or I want the same return, say 1 or 'ok' from all of them, etc.
UPDATE:
I agree this isn't the best code to test, here is an updated example of what I am trying to test in this case, so I need to stub MyUtil and the bar methods, these are static, so how do you suggest I refactor them? It doesn't make sense to me to put MyUtil as a required argument, and I would prefer to keep Foo as static if possible. A working test file would be super appreciated as I have been struggling with this kind of thing for a few days now.
public class Foo {
public static Object doSomething(Long id){
Bar bar = new Bar();
Object obj;
if(somecondition) {
Long vnumber = MyUtil.getVNumber(id);
obj = bar.getCurrentObj(id, vnumber);
} else {
obj = bar.getPreviousObj(id);
}
bar.z(obj);
....
}
}
Also, one of the points of this class was to make it a black box, I don't want the called to worry about creating instances and passing them in, or even knowing how things work, I just want to pass an ID and get a result for it. Some of the calling functions don't even HAVE access to Bar for example so I can't make it a required parameter.
Having so many methods to mock can be a sign of a class with too many responsibilities.
However, mocks are not the only test doubles. What might better suit your use case is a fake.
This would really depend on Foo being behind an interface:
interface Bar {
String x(String s);
String y(String s);
}
then you have your prod implementation:
class RealBar implements Bar {
#Override
String x(String s) {
// whatever your production logic is
}
}
and then a fake you use in the test that sits in your test source set:
class FakeBar implements Bar {
#Override
String x(String s) {
return "abc";
}
}
Because the fake works out-of-the-box, you can reuse it and you don't have to manually stub behaviors for it.
If you use constructor injection in Foo, your test will consist of passing in your fake Bar instead of the production Bar
#Before
public void setUp() {
foo = new Foo(new FakeBar());
}
Fakes are thus the accepted way of avoiding the burden of manually stubbing.
However, if you have no alternative to stubbing every single method of a class to return the same value, this is not a common use case and unlikely to be supported by most mocking libraries. Especially when Mockito tries to be opinionated on class design in order to prevent you from writing suboptimal code.
You could manually write code that used reflection to find the declared methods and then stub the behavior. By the time you do this, may as well have performed "Extract interface" and written a fake.
Imagine I had the following class structure:
class Parent {
public void method() {
// Some calculations
}
}
class Child extends Parent {
#Override
public void method() {
super.method();
// Some additional logic
}
}
I am spock-testing the Child.method and want to verify if the Parent.method is called from the Child.method. I did some research and i haven't found any satisfying solution to solve my problem.
How can I verify in a Spock test that in the call of Child.method the superclass method (Parent.method) was called as well?
Known solution: In Child move the super.method() to a separate, package-private method.
I want to know whether there is a better solution.
tim_yates commented:
Why do you want to test this? Can't you tell as the super class calculations were performed?
I completely agree. I would not test this because as #Override implies, the contract is an override, delegation to the super class method is optional. Why would you force your users to call the super class method? But as Tim said, you can test for the side effects which are important to you. Here is a little example with one side effect being a field assignment and another being something written to System.out (maybe silly, but just in order to show something non-obvious with a mock):
package de.scrum_master.stackoverflow.q60167623;
public class Parent {
protected String name;
public void method() {
// Some calculations
System.out.println("parent method");
name = "John Doe";
}
}
package de.scrum_master.stackoverflow.q60167623;
class Child extends Parent {
#Override
public void method() {
super.method();
// Some additional logic
System.out.println("child method");
}
public static void main(String[] args) {
new Child().method();
}
}
package de.scrum_master.stackoverflow.q60167623
import spock.lang.Specification
class ChildTest extends Specification {
static final PrintStream originalSysOut = System.out
PrintStream mockSysOut = Mock()
def setup() {
System.out = mockSysOut
}
def cleanup() {
System.out = originalSysOut
}
def test() {
given:
def child = new Child()
when:
child.method()
then:
1 * mockSysOut.println({ it.contains("parent") })
child.name == "John Doe"
}
}
Update: What you want to do simply is not possible technically, and for a reason: It would break encapsulation, see here, here, indirectly also here. The method is overridden, the word says it all. Test for the (side) effect or the result of a method, not for its interaction (that it is actually called). Spock's interaction testing capabilities are over-used even though the Spock manual warns about over-specification in some places. It just makes your tests brittle. Interaction testing is okay for design patterns like publish/subscribe (Observer pattern) where it makes sense to test the interactions between objects as such.
If you need to enforce that some functionality in Parent is called, you should enforce it via design not tests.
abstract class Parent {
public final void method() {
// Some calculations
additionalLogic();
}
protected abstract void additionalLogic();
}
class Child extends Parent {
#Override
protected void additionalLogic() {
super.method();
// Some additional logic
}
}
You could of course not make it abstract and just add a no-op implementation for additionalLogic() instead.
tim_yates and kriegaex are the big beasts in the jungle when it comes to good and bad Spock, or TDD-style testing generally ... they have more than once (rightly) picked apart my questions in the way they do here, basically on the basis of testing the code rather than the implementation.
Sometimes it's difficult though. Maybe there can be cases in which you would want to test for the calling of super.doSomething(). I am just putting together, using TDD, having already done a "spike", in which I rushed ahead without testing, an editor for a TreeTableView. The "spike" can be seen here. In a constructive comment to my answer, kleopatra advised me to check (i.e. put an if in the app code) to make sure that super.startEdit() had indeed started the editing of the cell before going further, so in this case it is not sufficient to test the "side-effect" of super.startEdit() as being that isEditing() now returns true. You genuinely need to know that your class's startEdit() actually does nothing more nor less than call super.startEdit().
However, I don't believe it can be done, and tim_yates or kriegaex would almost certainly have said how you could do that if it were possible.
My suggested TDD solution would therefore be something like this:
def 'super start edit should be called if cell is not empty'(){
given:
// NB has to be GroovySpy because isEmpty() is final
DueDateEditor editor = GroovySpy( DueDateEditor ){
isEmpty() >> false
}
when:
editor.startEdit()
then:
1 * editor.callSuperStartEdit()
}
class DueDateEditor extends TreeTableCell {
#Override
void startEdit(){
if( ! isEmpty() ) {
// this is the line you have to add to make the test pass
callSuperStartEdit()
}
}
def callSuperStartEdit(){
super.startEdit()
}
}
I think you have to "spawn" an artificial single-purpose method since there is, precisely, no side effect at all!
PS I will in fact parameterise this test so that it returns true to isEmpty() in the second call, and require the method NOT to be called in that case.
I´ve never used the Spock framework, but i think you can check the type of the instance in the Parent.method with instance of operator or reflection.
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.