Testing a Class Which Preserves Its State in Private Variables

Testing a class which preserves its state in private variables

After researching and discussing with some experts, I come up with the solution that if we want to test a class which preserve it's state then the functionality which is preserving the state should go under a separate class. Which will serve the same purpose as setting the variables as private. So, ZoneUpdateDetector should have a dependency for example: ZoneUpdateStatePreserver and it should keep the state which was previously inside ZoneUpdateDetector

What is wrong with making a unit test a friend of the class it is testing?

Ideally, you shouldn't need to unit test private methods at all. All a consumer of your class should care about is the public interface, so that's what you should test. If a private method has a bug, it should be caught by a unit test that invokes some public method on the class which eventually ends up calling the buggy private method. If a bug manages to slip by, this indicates that your test cases don't fully reflect the contract you wish your class to implement. The solution to this problem is almost certainly to test public methods with more scrutiny, not to have your test cases dig into the class's implementation details.

Again, this is the ideal case. In the real world, things may not always be so clear, and having a unit testing class be a friend of the class it tests might be acceptable, or even desirable. Still, it's probably not something you want to do all the time. If it seems to come up often enough, that might a sign that your classes are too large and/or performing too many tasks. If so, further subdividing them by refactoring complex sets of private methods into separate classes should help remove the need for unit tests to know about implementation details.

What is good practice to accessing package private variables?

Having accessors/mutators is usually handy even if it is some more code:

  • If you later introduce some logic when accessing/setting the variable, you can do it just in one place without the need to affect all the classes using the variable - you can easily add features as additional logging, lazy loading, security, validation, ...

  • You can later change the underlying representation of the field (eg return subtype in some cases)

  • You can later introduce lifecycle management of the returned object - eg. Return pooled/cached/singleton/.. object
  • You can later decide to return Proxy/decorated object instead without affecting callers

Generally, it is a good idea as it gives you more flexibility, preserves encapsulation and reduces coupling between objects.

Why are instance variables in Java always private?

Instance variables are made private to force the users of those class to use methods to access them.
In most cases there are plain getters and setters but other methods might be used as well.

Using methods would allow you, for instance, to restrict access to read only, i.e. a field might be read but not written, if there's no setter. That would not be possible if the field was public.

Additionally, you might add some checks or conversions for the field access, which would not be possible with plain access to a public field. If a field was public and you'd later like to force all access through some method that performs additional checks etc. You'd have to change all usages of that field. If you make it private, you'd just have to change the access methods later on.

If phone was private:

Consider this case:

class Address {
private String phone;

public void setPhone(String phone) {
this.phone = phone;
}
}

//access:
Address a = new Address();
a.setPhone("001-555-12345");

If we started with the class like this and later it would be required to perform checks on the phoneNumber (e.g. some minimum length, digits only etc.) you'd just have to change the setter:

class Address {
private String phone;

public void setPhone(String phone) {
if( !isValid( phone) ) { //the checks are performed in the isValid(...) method
throw new IllegalArgumentException("please set a valid phone number");
}

this.phone = phone;
}
}

//access:
Address a = new Address();
a.setPhone("001-555-12345"); //access is the same

If phone was public:

Someone could set phone like this and you could not do anything about it:

Address a = new Address();
a.phone="001-555-12345";

If you now want to force the validation checks to be performed you'd have to make it private and whoever wrote the above lines would have to change the second line to this:

a.setPhone("001-555-12345");

Thus you couldn't just add the checks without breaking other code (it wouldn't compile anymore).

Additionally, if you access all fields/properties of a class through methods you keep access consistent and the user would not have to worry about whether the property is stored (i.e. is a instance field) or calculated (there are just methods and no instance fields).

How to preserve state in a function?

Python does not have C-style static variables. However, you can simulate them with closures.

def make_add_one():
x = 0
def _():
nonlocal x
if x < 3:
x += 1
else:
x = 1
return x
return _

add_one = make_add_one()

for _ in range(5):
print(add_one())

There is a duality between objects (data with functions) and closures (functions with data); compare to the class defined by Carcigenicate (slightly modified):

class AddOne:
def __init__(self):
self.hello = 0

def __call__(self):
if self.hello < 3:
self.hello += 1
else:
self.hello = 1
return self.hello

add_one = AddOne()
for _ in range(5):
print(add_one())

One can see the following correspondences:

  • class AddOne ↔ outer function make_add_one
  • instance AddOne() ↔ inner function make_add_one()
  • instance attribute AddOne().hello ↔ non-local variable hello inside make_add_one

How to unit test private methods in Typescript

Technically, in current versions of TypeScript private methods are only compile-time checked to be private - so you can call them.

class Example {
public publicMethod() {
return 'public';
}

private privateMethod() {
return 'private';
}
}

const example = new Example();

console.log(example.publicMethod()); // 'public'
console.log(example.privateMethod()); // 'private'

I mention this only because you asked how to do it, and that is how you could do it.

Correct Answer

However, that private method must be called by some other method... otherwise it isn't called at all. If you test the behaviour of that other method, you will cover the private method in the context it is used.

If you specifically test private methods, your tests will become tightly coupled to the implementation details (i.e. a good test wouldn't need to be changed if you refactored the implementation).

Disclaimer

If you still test it at the private method level, the compiler might in the future change and make the test fail (i.e. if the compiler made the method "properly" private, or if a future version of ECMAScript added visibility keywords, etc).



Related Topics



Leave a reply



Submit