I am working on a Selenium + java project where all Web Element in a class are declared as –
public class CheckoutPaymentConfirmpage extends WebPage{
public final Button btnPrintorder = new Button("//input[@id='but_Print']");
public final TextField txtpassword = new TextField("password", "//input[@id='pass']");
// Some more elements here
// Some page object methods here
}
Now when ever test need to access these elements they are directly invoked over the object of CheckoutPaymentConfirmpage
class
What ever little java (or OOPS) I know, has taught me that members should be as hidden as possible. Hence I would have had btnPrintorder
and txtpassword
declared private and would access them using getters or would have created methods in page object class to be used by tests.
But when I convey this to others they don’t see much value in it as state of instance variable (i.e. btnPrintorder
etc) would not be changed from one object to another for page object class (i.e. CheckoutPaymentConfirmpage
etc)
Hence in this situation, is it ok to leave instance variable as public?
Page Object elements should be private. The issue, especially with respect to the Page Object pattern, is that public objects expose their methods, not the page object’s methods. If the page object’s method would just be clickPrintButton()
, there’s not much difference, but imagine instead a printOrder()
method that needs to click the button and wait for a confirmation message to appear. And even in the simple case, ask yourself what other methods can be applied to a Button
object, and do you want the consumer of the CheckoutPaymentConfirmpage
to use them.
2
If memory serves, the reasons for developing the technique of encapsulating members with accessor/mutator pairs are due to some historical problems associated with maintenance and quality control.
As a programs grows, is maintained, and new features added, some of the particular problems are:
-
A bug emerges where the value of the member is incorrect, but it is difficult to determine why it was set they way it was. The value may even be used to for a different purpose by a caller.
-
The source of the values for that member change. Rather than being set ahead of time, the value needs to be fetched rather that recited.
The encapsulation helps to solve the problem by ensuring that the class’s maintainer has a function which can be modified to take control of the value being set or retrieve and ensure that it is correct.
This is similar to programming practices such as minimizing the scope of variables, and maximizing cohesion. The approach also embodies the secure coding practice of validating and verifying inputs and outputs. (A class represents one clear concern / state-machine, etc.)
Should this be applied to your particular situation? Can you accurately predict and control the future of the software? Consider that if you encapsulate and never need it, you’ve lost a few minutes of IDE generated functions. If you don’t do it and later need it, it can be economically expensive to fix, (especially in a larger program).
More concisely, encapsulating access to class members consistently as a rule is a typical technique for mitigating economic risks in software quality and maintenance.
You misunderstand implementation hiding if you think that making members private, but providing getters and setters, is information hiding.
If I’m using your class, and I have a way of directly accessing a member via a getter, or overwriting that member with a setter, then it isn’t information hiding. Your class is acting as a dumb container for members that I can manipulate quite directly.
Yes, the getter and setter can do some neat things, like trigger certain actions. Maybe the getters and setters can be rewritten to be remote procedure calls to a server in Russia. But those neat things are not information hiding. They don’t hide how the class is implemented, only some details about how that specific member is implemented.
In any case, in decent programming languages, if you need that kind of abstraction for member access, you can just start out by leaving an ordinary member accessible, and then later add getter and setter methods which hook into the ordinary access syntax. That is to say, an assignment like obj.memb = foo
actually triggers a setter, and evaluation of obj.memb
triggers a getter. Getters-setters versus direct evaluation and assignment syntax is therefore only an issue of syntax, whereas implementation hiding has to do with semantics, and revolves around providing no access to members whatsoever. An object which hides its implementation can only be manipulated by methods on that object, none of which provide direct access to any members.
1