Reputation: 1270
Are there any disadvantages in using a private accessor to test a piece of code?
I'm weighing the option of using a private accessor only to test my GUI, as opposed the the methods/properties that are publically exposed.
This will allow some GUI testing i need, i just wanted to make sure their were not any hidden "pitfalls" in using a private accessor in how it behaves.
Upvotes: 2
Views: 394
Reputation: 64218
So to recap, your stated goal is:
I'm weighing the option of using a private accessor only to test my GUI... This will allow some GUI testing i need...
In short, yes there are pitfalls. The code you are testing is still tightly coupled to the user interface.
In the comments you clarify your goal/problem as:
What about in the case if i want to test, Drag/drop. Custom Controls, Overriden events?
All I can say is welcome aboard. The software industry has struggled with this for nearly half a century. The fact remains that testing UI is hard, Really HARD. Yes you can take a piece of code that is tightly coupled with a UI element and try and automate it; however, your going to be fighting tooth-and-nail to make headway against poor assumptions.
The 'trick' to testable UI is not to make your UI testable, but to remove the code you want to test from the UI. Thus the wide acceptance of N-Tier application development and presentation design patterns like MVC, MVVM, etc.
see the following:
The primary goal or driving force behind many of these design patterns is to remove the tight coupling between behavior and presentation. This enables you to then test a behavior like drag-n-drop without a user interface. My recommendation is review the patterns, choose one you like, and then start refactoring the code as you write your unit tests.
Another way to think of writing UI for testing is to remove every if, else, for, while, switch, or other control statement from your user interface code. The resulting 'shell' of a UI should be very resilient to change. Just be careful when using things like data binding that rely on reflection (which is generally an acceptable practice). The primary downside to this is that the compiler can not tell you that a member no longer exists.
Updated
@timmy you wrote:
... for example if i want to test mouse click behavior...
So what about the mouse click behavior cannot be moved to a controller rather than being embedded into the form? I guess the "Close" button might have a problem, but beyond that why not move the logic to another class that can then be tested?
BTW, You don't have to pick just one pattern MVC, MVVM, etc, they are 'guidelines' or 'suggestions' not hard rules so don't get ridiculous with it. Just try and make the logic separate from the UI and independently testable. As an example, perhaps your "Click" event fits better with a simple command class? Using a command pattern is easy, new up an object and execute it. Consider this example code for a folder copy form:
private void OnCopyClick(object sender, EventArgs args)
{
var cmd = new MyCopyCommand(this.FolderPath, this.txtTargetFolderPath.Text);
new ErrorHandler(this).Perform(cmd);
}
This works well, it has no 'real' logic other than what to provide the command and has no conditional code paths. Notice we don't even directly invoke the command but rather defer that to someone who can handle an error appropriately. Usually this 'ErrorHandler' would be provided to the Form rather than constructed directly, but you get the idea.
From this we should be easily able to verify the correct behavior of the MyCopyCommand. In the end you should wind up with a bunch of "flat functions" in the UI, ie. functions that have no nesting or curly braces. Of course this is a rule of thumb, not to be taken to such an extreme as to prevent you from being productive.
I know this may seem like a lot of work, but truthfully it is not when you are already working to write a set of tests. You can be productive AND write solid code. You just need to know when to cheat, and when not to. That comes with experience and after 20 years, 10 of those writing NUnits, I still fail once in a while. When something breaks because you didn't do this, first extract the logic from the UI, then write a unit test to prove it's broken, then fix it.
Upvotes: 1
Reputation: 11088
In addition to what AD.NET said. I could use those private properties in tests only until I finish my refactoring (to Model View Controller, Model View Presenter, Model View ViewModel) so that I don't have to test GUI at all!
Upvotes: 0
Reputation: 13399
It's better not to use them, instead try to find out if you can inject any dependency. Unless you're working on a legacy code where you want to create some unit tests using private accessors, I'd suggest not to use them and even in this case, I'd recommend you do that temporarily until you refactor legacy code.
Upvotes: 1