Under what conditions should I test get() and set() methods? - java

I could not confirm whether to do these tests. It seems the set and get method is so simple,such as:
setA(String A) {
this.A = A;
}
getA(){
return A;
}
Any ideas would be appreciated!
Thanks,
Joseph

I've only seen a very few problems with getters and setters in the wild, and only one of those could have been detected via a unit test, and only then if all of the getters and setters were tested together, rather than by individual test methods.
Consider the copy/paste mistake of reusing the same field from two different pairs of getters/setters. I.e.,
public void setA(Object a) {
this.a = a;
}
public Object getA() {
return a;
}
public void setB(Object a) {
this.a = a;
}
public Object getB() {
return a;
}
Unit tests that focus on one setter/getter pair at a time won't expose the problem.
Modern IDEs will generate getters and setters on request, so this mistake is unlikely, but not everyone uses modern IDEs. (A vi user created the bug above.) And if these methods reside in a simple data-holder object, the problem may only show up a bit far from the cause.
For this reason, if I test getters and setters at all (and I often don't), it's from a single test method that calls all of the setters first with distinct values, then asserts on all of the getters.
One problem you've got to live with, though, is that there's no guarantee that a method that starts life as a "simple" getter or setter will stay that way when someone else gets their hands on the code and decides, say, that a getter is a good place do something that involves a side-effect.

General rule: Not much point in writing tests for getters and setters. Only if they have some additional logic, ie. are not pure accessors, you should write the tests.

The only time I would write tests specifically for set() and get() methods, is if there is some sort of logic inside them. Eg. limit an integer to between 1 and 8
public void SetA(int a)
{
if(a > 8 || a < 1)
{
throw new IndexOutOfBoundsException();
}
this.a = a;
}
Even though the code above is a very simple example, when you do this type of logic, it can be a good idea to run a test on them. Mainly for when your business rules change and you have to limit it to between 9 and 1 :)

A smart man once said "Test until fear turns to boredom". If you no longer fear that your super-simple code will break, don't write tests unless you're not bored writing those tests. And don't write tests just to "improve your metrics," that's just gaming the system. Write tests to make sure your code works, to improve robustness, and to create confidence that you can refactor freely.

Make a cost/benefit analisis
What would it gain
knowing that the private variable indeed get read/written
What would it cost
the time taken to write the testcase
the time spend, each time executing your testsuite
If you know there are no observable side-effects calling the getter or setter, I wouldn't bother.

Yes, in your case they are trivial - but on the other hand - two simple tests that fully count for quality metrics ;-)
I would create tests. Your application actually relies on the behaviour that the methods really store/access the field values and do not change anything.
Maybe, one day someone decides to change a field type or to add some unit conversion code to a setter/getter - a test will show, if the code still works or it will show, that more work is needed.

They are all same, I say like blank interfaces or business classes. Preprocessing should enable all needed or they are other kinds (doers that both shall return like respond and take 2 variables) language agnostically (even POSIX exit that now is void should use arguments since knowing way is very important)

Writing test cases for methods which can't fail seems disproportionate to me.
Only if the value of A is initialized by configuration or something which could fail
it is worth testing.
EDIT:
Another example when testing makes sense could be a flag 'overdrawn' if an accounts balance becomes negative and you want to check whether the flag was set correctly after calling a method withdraw().

Unit tests are supposed to be the documentation for how the system is supposed to work. Although people often skip unit tests for Properties because the functionality is trivial,
if the tests are the documentation and especially if someone else is going to do the implementation then tests for Properties should be written.
That said, when I am both writing the tests and doing the implementation, I usually skip writing tests for Properties unless they do something more than a simple get/set or if I have spare time, which is a rare thing.

Related

How to testing something like a converter

i have a question regarding testing classes like a converter.
Lets say i have a converter from EntityA to EntityB. The converter seems like this:
public EntityB convert(EntityA){
//call interal methods
return B.
}
private xy internalMethod1(...){
//call other interal Method
}
private xy internalMethod2(...){
....
}
private xy internalMethod3(...){
....
}
private xy internalMethod4(...){
....
}
The converter has one public method and 4 internal methods to convert the entity.
How should i test it?
Option1
I only test the public method and cover all cases from the internalMethods by different example inputs.
Advantages:
Testing only the "interface". Dont know the interal structure.
Internal refactoring is very easy and needs no changes at the tests.
Disadvantages:
Really big maybe unclear tests that tests all cases.
Every input must be pass all the methods.
Option2
I write tests for my public method and my private methods. (Some testframeworks can access private methods like powermock or spock (groovy))
I test every method alone and mock every other internal method.
Advantages:
Really small tests that only test the method itself and mock all other methods .
Disadvantages:
I know how it is implemented internal and must change the tests if i refactor some method, some methodname or something at the internal calling structure
Option3
I write some new classes that do the internal stuff and have public methods
Advantages:
Tests are maybe clearer and only for the special classes.
Disadvantages:
More classes for one conversion task.
Please help me what is the best practise here.
Maybe some good links/hints.
Thank you for your time.
The points you make are valid, but I think you might not be estimating their weight correctly.
Writing brittle tests (tests that are coupled to the implementation code) makes for a rigid code base that is hard to change. Since the point of writing tests in the first place is to be able to go fast, this is counter productive.
This is why you write your tests through the API only - it decouples the tests from the implementation. As you've said, this might make writing the tests a bit harder, but the reward is worth the effort since you'll get safety and be able to refactor easily.
Option 3 comes into play when you see a code smell where some tests cover only some of the code, and other tests only cover the other part of the code. This usually means there's a collaborator that maybe needs to be extracted. This is especially true when some internal functions only use some parameters and others don't. Also, when there's code duplication and the like.
What I would suggest, is to write it using the way you described in option 1, and then extract code out if needed, in the refactoring stage.

Should I test (duplicate) data, or only the behavior?

From the design perspective, I am wondering should I test the data, especially if it's a generally known data (not something very configurable) - this can apply to things like popular file extensions, special IP addresses etc.
Suppose we have a emergency phone number classifier:
public class ContactClassifier {
public final static String EMERGENCY_PHONE_NUMBER = "911";
public boolean isEmergencyNumber(String number) {
return number.equals(EMERGENCY_PHONE_NUMBER);
}
}
Should I test it this way ("911" duplication):
#Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber("911"));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
or (test if properly recognized "configured" number):
#Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber(ContactClassifier.EMERGENCY_PHONE_NUMBER));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
or inject "911" in the constructor,which looks the most reasonable for me, but even if I do so - should I wrote a test for the "application glue" if the component was instantiated with proper value? If someone can do a typo in data (code), then I see no reasons someone can do a typo in tests case (I bet such data would be copy-paste)
What is the point in test data that you can test? That constant value is in fact constant value? It's already defined in code. Java makes sure that the value is in fact the value so don't bother.
What you should do in unit test is test implementation, if it's correct or not. To test incorrect behaviour you use data defined inside test, marked as wrong, and send to method. To test that data is correct you input it during test, if it's border values that are not well known, or use application wide known values (constants inside interfaces) if they're defined somewhere already.
What is bothering you is that the data, that should be well known to everyone) is placed in test and that is not correct at all. What you can do is to move it to interface level. This way, by design, you have your application known data designed to be part of contract and it's correctness checked by java compiler.
Values that are well known should not be checked but should be handled by interfaces of some sort to maintain them. Changing it is easy, yes, and your test will not fail during that change, but to avoid accidents with it you should have merge request, reviews and tasks that are associated with them. If someone does change it by accident you can find that at the code review. If you commit everything to master you have bigger problems than constants doubly defined.
Now, onto parts that are bothering you in other approaches:
1) If someone can do a typo in data (code), then I see no reasons someone can do a typo in tests case (I bet such data would be copy-paste)
Actually, if someone changes values in data and then continues to develop, at some point he will run clean-install and see those failed tests. At that point he will probably change/ignore test to make it pass. If you have person that changes data so randomly you have bigger issues, and if not and the change is defined by task - you made someone do the change twice (at least?). No pros and many cons.
2) Worrying about someone making a mistake is generally bad practice. You can't catch it using code. Code reviews are designed for that. You can worry though about someone not correctly using the interface you defined.
3) Should I test it this way:
#Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber(ContactClassifier.EMERGENCY_PHONE_NUMBER));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
Also not this way. This is not test but test batch, i.e. multiple tests in the same method. It should be this way (convention-s):
#Test
public testClassifier_emergencyNumberSupplied_correctnessConfirmed() {
assertTrue(contactClassifier.isEmergencyNumber(ContactClassifier.EMERGENCY_PHONE_NUMBER));
}
#Test
public testClassifier_incorrectValueSupplied_correctnessNotConfirmed() {
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
4) it's not necessary when method is properly named, but if it's long enough you might consider naming the values inside test. For example
#Test
public testClassifier_incorrectValueSupplied_correctnessNotConfirmed() {
String nonEmergencyNumber = "111-other-222";
assertFalse(contactClassifier.isEmergencyNumber(nonEmergencyNumber));
}
External constants as such have a problem. The import disappears and the constant is added to the class' constant pool. Hence when in the future the constant is changed in the original class, the compiler does not see a dependency between the .class files, and leaves the old constant value in the test class.
So you would need a clean build.
Furthermore tests should be short, clear to read and fast to write. Tests deal with concrete cases of data. Abstractions are counter-productive, and may even lead to errors in the test themselves. Constants (like a speed limit) should be etched in stone, should be literals. Value properties like the maximum velocity of a car brand can stem from some kind of table lookup.
Of course repeated values could be placed in local constants. Prevents typos, easy - as local - abstraction, clarifies the semantic meaning of a value.
However as cases in general will use constants maybe twice or three times (positive and negative test), I would go for bare constants.
In my opinion the test should check behaviour and not the internal implementation.
The fact that isEmergencyNumber verifies the number over constant declared in the class you're trying to test is verification over internal implementation. You shouldn't rely on it in the test because it is not safe.
Let me give you some examples:
Example #1: Someone changed EMERGENCY_PHONE_NUMBER by mistake and didn't notice. The second test will never catch it.
Example #2: Suppose ContactClassifier is changed by not very smart developer to the following code. Of course it is completely edge case and most likely it will never happen in practice, but it also helps to understand what I mean.
public final static String EMERGENCY_PHONE_NUMBER = new String("911");
public boolean isEmergencyNumber(String number) {
return number == EMERGENCY_PHONE_NUMBER;
}
In this case your second test will not fail because it relies on internal implementation, but your first test which checks real word behaviour will catch the problem.
Writing a unit test serves an important purpose: you specify rules to be followed by the method being tested.
So, when the method breaks that rule i.e. the behavior changes, the test would fail.
I suggest, write in human language, what you want the rule to be, and then accordingly write it in computer language.
Let me elaborate.
Option 1 When I ask ContactClassifier.isEmergencyNumber method, "Is the string "911" an emergency number?", it should say yes.
Translates to
assertTrue(contactClassifier.isEmergencyNumber("911"));
What this means is you want to control and test what number is specified by the constant ContactClassifier.EMERGENCY_PHONE_NUMBER. Its value should be 911 and that the method isEmergencyNumber(String number) does its logic against this "911" string.
Option 2 When I ask ContactClassifier.isEmergencyNumber method, "Is the string specified in ContactClassifier.EMERGENCY_PHONE_NUMBER an emergency number ?", it should say yes.
It translates to
assertTrue(contactClassifier.isEmergencyNumber("911"));
What this means is you don't care what string is specified by the constant ContactClassifier.EMERGENCY_PHONE_NUMBER. Just that the method isEmergencyNumber(String number) does its logic against that string.
So, the answer would depend on which one of above behaviors you want to ensure.
I'd opt for
#Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber("911"));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
as this doesn't test against something from the class under test that might be faulty. Testing with
#Test
public testClassifier() {
assertTrue(contactClassifier.isEmergencyNumber(ContactClassifier.EMERGENCY_PHONE_NUMBER));
assertFalse(contactClassifier.isEmergencyNumber("111-other-222"));
}
will never catch if someone introduces a typo into ContactClassifier.EMERGENCY_PHONE_NUMBER.
In my opinion that is not necessary to test this logic. The reason is: this logic is trivial for me.
We can test all line of our code, but I don't think that is a good idea to do this. For example getter and setter. If we follow the theory to test all line of code, we have to write test for each of getter and setter. But these tests have low value and cost more time to write, to maintain. That is not a good investment

Unit Testing and White Box Testing

Currently, I'm in a position where I'm to write unit tests for source code I have complete visibility of (which I think means it's considered white box testing?). So, this isn't test-driven development.
Reading this (What is the difference between integration and unit tests?) clarified a lot about what the purpose of all this is, but I'm confused about my current position still.
Let's say I have a method like so:
/* Some basic description on what doSomething() does */
public int doSomething(Var someVariable) {
int someInteger = [code does a bunch of stuff to get this];
someInteger = someOtherClassObject.doSomethingElse(someInteger);
return someInteger;
}
Now, I don't really know what doSomething() is supposed to do. The documentation isn't enough to really tell me what int is supposed to come out based on someVariable, and I'm not familiar enough with the source code to really come up with it myself.
But I do have the implementation, so I look at the method, put in some Var as the input, and follow the code and assert against what it looks like it would return.
public void testDoSomething() {
ClassWithDoSomething object = new ClassWithDoSomething();
assertEquals([what it looks like it would return], object.doSomething(new Var([some input would go here]));
}
Where some way, somehow, I mock out the doSomethingElse() call and the Var constructor (and other external class dependencies if need be).
I don't know whether this is the right way to go about these unit tests. I think I'm isolating the method as I should, but I don't know how meaningful my assert is in determining whether there is a bug or not, because I know just what the method doSomething() is supposed to do in code, and how it's going to go about it, and so I've written my assertion to get that result.
The answer I've read details how unit tests are beneficial due to the method doSomething()'s isolated failure. But when would its unit test ever fail, other than when doSomething()'s implementation changes (which would mean a change in the unit test)?
Is this an issue of not knowing the source code well enough/the source code not being well documented enough to just be able to know what output I should be getting?
If [code does a bunch of stuff to get this] was really just someVariable + 3 where someVariable was an int, is it considered a meaningful assert to assert that the return value is someVariable + 3 when I know the test is going to pass based on that implementation?
But when would its unit test ever fail?
You have it exactly right; the unit test will fail when doSomething's implementation changes. The point of the unit test is to catch it when a seemingly-innocuous change actually breaks the method.
Unit tests often look similar to the code snippet you posted:
public void testDoSomething() {
ClassWithDoSomething object = new ClassWithDoSomething();
object.someOtherClassObject = new MockOtherClass();
assertEquals(4, object.doSomething(new Var("Input that maps to 4"));
}
Both SomeOtherClass and MockOtherClass implement an IOtherClass interface that specifies doSomethingElse. MockOtherClass simply returns the input when you call its doSomethingElse method.
i'd say it's pointless to write unit testing if you don't know what the code is expected to do.
unit testing is checking if given some input code behaves correctly. if you don't know what does 'correctly' mean then how can you test it? you have to understand intention of the code before writing valuable tests.
the situation is a bit different if you write tests in order to rewrite the source code from scratch. in this case tests are the best safety net you can get because they document the actual behaviour and guarantee it won't change. but even in this case, without knowing what the code does, it's easy to miss some corner cases.
so i recommend to always know the intention of the code before you write tests.

Should we check no changes in unit tests?

This example is custom made to ask my doubt.
Object Car {
color:null
tyre : 0;
}
fillCar(Object Car, boolean b) {
if (b) {
Car.color = "Red"
} else {
Car.tyre = 4;
}
}
Now i need to unit test my code.
My test1 is (Car, true) and test2 is (Car, false).
My question:
Do i need to test "tyres == 4" when in test1 and on similar lines do i need to check "color == null" when test2 ?
The answer is YES if this is part of the functional requirement of the method.
For example, if your specifications say that when True the value of tyre must be 4 and other variables will not matter, then it is not necessary. But if your specifications say that not only tyre must be 4 but the rest of variables must remain with the same value, then you should check that out too.
Take into account that Unit test not only are useful for checking that your code is fine, but also for making sure that when your code in the future, you do not corrupt the expected functionality.
Generally, there is no harm in testing all parts of the code. In fact, I would encourage it. It's a very easy way of checking that no mistakes have been made in the logic.
In this case, the code is simple enough to see the result. However, it could become much more complex if Car is extended, or more functionality added.
There is a lot of argument about this but unit testing started to make sense to me once I focused on verifying the interface. In this case you have a function which exposes an interface where you can pass in a car-object and a boolean and then have certain modifications made to the car object depending on the value of the boolean. You quite rightly see two unit tests covering that and personally I would stop there. If you are worried about nulls showing up you can cover that in the unit tests when the car objects are constructed. If you assign something other than a straight forward literal that might be a null then tests for nulls would make sense.
One more tip - unit testing works much better for me within the context of test driven design (TDD). YMMV but I find non-TDD code very hard to unit test.
Finally - just a mention that I found learning TDD/unit-testing is well worth it.

Is it correct to isolate a unit test at method level and stub internal method calls?

I always have the doubt if unit testing isolation should be done at very fine grain like stubbing internal method calls, look at the following example with Java, JUnit and Mockito.
package com.company.domain;
public class Foo {
private FooHelper helper;
public setHelper(FooHelper helper) {
this.helper = helper;
}
public Double method1(Integer a, Integer b) {
... // logic here
Integer var = method2(a); // internal call to method2
... // more logic here
}
protected Integer method2(Integer c) {
... // logic here and return an Integer
}
}
This is the test class:
package com.company.domain;
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
#Mock private FooHelper fooHelperMock; // mocking dependencies as usual
#InjectMocks #Spy Foo foo; // this way we can stub internal calls
#Test
public void method1Test() {
doReturn(2).when(foo).method2(1); //stub the internal method call
... // stub fooHelperMock method calls here
Double result = foo.method1(1, 2);
assertEquals(new Double(1.54), result);
verify(foo, times(1)).method2(1);
... // verify fooHelperMock method calls here
}
#Test
public void method2Test() {
... // stub fooHelper method calls here
assertEquals(new Integer(5), foo.method2(3));
... // verify fooHelperMock method calls here
}
}
I think this way you are able to really isolate the code under testing at method level even with internal calls. But I cannot find lot of information about this being considered a good practice or not and why.
In general, testing a class's internal function calls makes your tests far too fragile. When unit testing, you only want to see that the class as a whole is doing what it is supposed to do. You are supposed to intentionally ignore the internals.
Ignoring the internals has a lot of useful benefits. Mainly, if you change the methods -- as long as the public interface stays the same -- your tests will all still pass. Yay. This is the type of stability you want your unit tests to have. Fragile unit tests are almost worse than no unit tests. A fragile test has to be changed every time the code changes even if everything is still working. That provides you with nothing but extra work.
There are exceptions though. I would consider mocking out internal function calls in the following cases:
1) The internal call pulls data from somewhere. For example a database or large file. This is often called a 'boundary' test. We don't want to really set up a database or file to test, so instead we just sub out the function. However, if you find yourself doing this, it probably means that your class should be split into two classes because it is doing too many different things. Make yourself a dedicated database class instead.
2) The internal call does heavy processing that takes a lot of time. In that case, it might make sense to sub out the function instead of waiting. However, once again this might be a sign that you're on the wrong track. You should try to find a way to make things more partitioned so no single step takes that long.
In conclusion, I would highly recommend you do not test at the method level. A class should be a distinct unit. If the class is working everything is fine. This approach give you the testing you need to be secure and the flexibility you need to change things.
#raspacorp
Indeed, if you only test one case, someone could hardcode var = 2 and then pass your test case. But it is your job in designing tests cases to cover enough different cases to be reasonably satisfied that it is behaving appropriately.
As far as tests changing because the code has changed, this is not what you want at all. You want your tests to verify that the responses you are getting are correct for all the different types of cases. As long as the responses are correct, you want to be able to change everything without changing the tests at all.
Imagine a large system with thousands of tests verifing that everything is working right. Now imagine that you want to make a HUGE optimization change that will make things go faster, but change how everything is stored and calculated. What you want your tests to allow you to do is only change code (not tests) and have the tests continually confirm that everything is still working. This is what unit tests are for, not catching every possible line change, but rather to verify that all the calculations and behaviors are corrent.
This article from Martin Fowler answers your question.
You're a mockist, as I'm, but there are many people who don't like this approach and prefer the classicist approach (e.g. Kent Beck).
Roy Osherove says that the goal of a test, when it fails, is to identify the production code causing the problem, and having that in mind is obvious that the more fine grained the better.
For sure being a mockist may be overwhelming for beginners, but once you're used to the mechanisms of a Mocking library the benefits are uncountable while the effort is not much higher than the other approach.
I do not think it is necessary and I would even go further to say you should not do this. You are writing more test code to test less of you application code. In general it is considered good practice to only test public methods, because a unit test should only be concerned whether a method under test satisfies its contract (i.e. does what it is supposed to do) and not how the method is implemented. If you have a bug in your private method, how will you know?

Categories