I'm working on a project that provides a library of related functionality to other groups within the company...
It recently became apparent that the library is being used by other groups in ways that makes it unstable - so my task is to limit scope of classes within the project so that only one singleton class is used as the entry point to the project.
What I've done
1) removed the "public" class modifier from "internal" classes
2) set methods to "protected"
Result
this update has been great because classes that are not meant to be exposed are now inaccessible outside of the project.
HOWEVER, the test cases are now not building due to the limited scope.
The person who wrote the test cases wrote the code in such a way that classes are instantiated individually and manipulated. This is no longer possible due to the limited scope (the test cases are in another package).
Question
To rectify this, should the test cases access the inner (private) classes through the singleton, or is there another way ?
Put your tests in the same package! If you want to keep them apart, just put them in another directory:
.
└── src
├── main
│ └── com.my.package
└── test
└── com.my.package
Your code should be written in a way that facilitates your unit tests. Internal implementation specifics not accessible via a public api are normally tested via your public apis.
Also, assuming we're talking about JUnits here, by convention your tests should be in the same package, not a different package. If there were, then even if your methods are default/package visibility, the tests in the same package can still access that code.
You should write your code in a way that makes it easy to test - if you find yourself doing things that seem far too hard, then you've most likely making it hard for yourself. Go back and look at the code again and see if you can refactor it to make it easy to test.
There is a way, but out of due diligence I must echo what others have said and say that test classes should be in the same package. Any approach that differs from this will be painful. Either you will take longer to write the extra bit of code to access the inner class data or you will write code which is not testable. There is no benifit to not doing this that I am aware of or that you have stated.
What you have said about your library that users are easily writting code which is 'unstable' means that you have made some design errors in your API, nothing to be ashamed of we have all done that.
In addition it also concernes me the way you are talking about single point of entry and singletons. The most obvious use-case for singleton is for performing operations on a file. If you had multiple instances which had this prevallige you could have allot of locking going on and writting at the same time. I don't think the pattern is good for controlling how people use your library.
As hard as it is to say to me it sounds like you have some design flaws and that you have some particular problems you are trying to solve which are really just symtoms of these flaws, and cannot really be fixed any simple way.
Related
I am currently writing Selenium WebDriver tests for a variety of websites each using the same proprietary framework.
Because of this, there are many test cases that can be quite similar across different websites. As such I have made my test classes as generic as possible and made it so that every XPath/CSS Selector/ID used to locate elements is defined in a Constants class, which is unique to every project.
But, in some cases, the code for the same test can be the same across different websites, since I wrote them generically.
In addition each test is a direct/indirect extension of a BasicTest class which contains code that is likely to be reused by different tests (ex: WebDriver instance declaration, etc)
The way I thought about setting my test structure was the following:
one generic project that is "reused" by each subsequent project;
one project per website with its own definition of the Constantsclass and a TestSuite class that it can use to run both generic tests and tests specific to itself.
This would allow me not to have copies of these generic tests in each of my test projects.
The problem is that I don't really know how to set this up. The GenericProject is going to contain tests that require variables from Constant, but it makes no sense to have generic Constants. Plus, will I be able to call those tests inside my website project-specific TestSuites? If I redefine Constants in each specific project, will those constants be used for the generic tests defined in GenericProject?
How can I even set it up so that I can reuse Project A's classes inside of Project B, C, D... etc?
Extract your constants to a properties file which exists in each module as src/test/resources/common.properties.
Use org.apache.commons:commons-configuration2 PropertiesConfiguration to read this file. It will handle nested properties just fine.
Common code can be shared by depending on your GenericModule. Official instructions for two models of doing this (extract common tests to a new module or use a test-jar) are here
In general in order to reuse code over projects you would create a library containing the reusable code. In order to do so you'd need to think about a suitable API for the library.
This contains decisions about:
How will functionality be called from dependent code
How will dependent code provide required data.
If you are using constants for e.g. CSS selectors, that are different but have the same semantics, e.g.
root frame
side panel
main area
...
you might want to define an interface that the dependent code can provide. This could look like:
interface CssSelectors {
String rootFrame();
String sidePanel();
//...
}
If you are building this for tests you might also want to use features of your test framework (e.g. Rules in JUnit).
When reusing code in tests you also should consider another aspect:
If s.o. reads the tests written with your library, will she be able to sufficiently understand what is happening behind the border of the library to understand what the test is all about? This is a lot more of a question when dealing with test code than with production code as for test coverage and validity of tests it often matters a lot more how a setup or verification is done than is the case for production code.
I was working with Typescript and Javascript and I stopped for a bit thinking about namespaces and how we organize code in Java.
Now, pretty often I see multiple classes with the same purpose, just for use with different data, being placed in different packages with different names.
While placing those classes in different packages is a good practice to maintain the project/module in a good state, why would we have to give them different names? I mean, their purpose is the same.
I can answer this question myself: because often we use those classes inside the same unit and they would clash, thus requiring a long full package specification for one or the other.
But aren't we violating the DRY principle? We should use our directory (package) structure to understand in which domain space those classes works.
As I wrote above, I suppose many developers aren't respecting this DRY principle just to avoid long package names. Then, why are we creating those monstruos package hierarchies?
Googling "Java packages best practices" results in suggestions such as:
com.mycompany.myproduct.[...]
Where do those suggestions come from? Aren't we just wasting space?
We obviously do not want to write that every time.
MyClass myInstance;
com.mycompany.myproduct.mypackage.MyClass myOtherInstance;
But it could have been
myfeature.MyClass myInstance
myotherfeature.MyClass myInstance;
We could even specify the full package for both.
So, where do those best practices come from?
As it has been said, this convention dates back to the first releases of Java.
Name clashes could be easily solved by qualifying the imported dependency (such as a classpath library) classes with their short packages' hierarchy, emphasizing and keeping cleaner our own code. It is also important to remember we have access to the package-level visibility, which seems overlooked nowdays.
As a commenter points out, this convention was established at the very beginning of Java, to allow a global namespace to be used for all classes.
One thing about Java that influences this -- and is different from TypeScript and JavaScript -- the name of a class and its package (as well as all the names of classes and packages it uses) is fixed at compile time. You can't recombine classes into a different hierarchy without modifying their source code. So it's not as flexible as an interpreted language where you can just move the hierarchy around and change the locations from which you load code.
You can, of course, put everything in your application in the top-level package, for example, and be pretty confident you'll get away with it. You'll be able to do that as long as everyone else follows the existing convention. Once they stop doing that, and libraries start putting classes wherever they want, you'll have collisions, and you'll have to change your application. Or libraries will start colliding with each other, and if you don't have the source, you won't really be able to fix it.
So there are good reasons.
My opinion-based part of this -- sticking with conventions and a language's (or platform's) culture makes sense. Even if the conventions are silly, in our view. There's a place for breaking them but the advantages have to be pretty big. Other developers will be used to the convention, tools will make assumptions about the conventions ... usually it makes sense to go with the flow.
Does it really make sense to use getters and setters for every property in Java? If you understand the domain you're using well, it very well might not. But stop doing it and your code isn't going to make sense to other members of your team, you'll have to continuously revisit the decision as people join, and so forth.
If it's a one-person project and always will be, of course, you can do what you want.
I just googled "Joshua Bloch TDD"... not much came up, which is a huge shame because I'd really like to know what he's got to say on the matter.
Item 13 (I'm looking at the 2nd edition) is entitled "Minimize the accessibility of classes and members". After a couple of pages he says:
To facilitate testing, you may be tempted to make a class, interface
or member* more accessible. ... It is acceptable to make a private
member of a public class package-private in order to test it, but it
is not acceptable to raise the accessibility any higher than that...
Luckily, it isn't necessary either, as tests can be made to run as
part of the package being tested, thus gaining access to its
package-private elements.
* by "members" he means "fields, methods, nested classes and nested interfaces".
As a TDD newb, but gradually finding my feet, I am aware that the current consensus seems to be not to include testing classes with the app code packages, nor even to have a matching structure under src\test and src\main: mostly TDD experts readily seem to structure their testing directories in other ways (e.g. you have one directory called "unittests" another called "functionaltests" and another called "e2etests").
Specifically, I have followed the TDD development of the auction app in "Growing Object Oriented Software Guided by Tests". The author there has no qualms about adding hundreds of public methods. Furthermore, after one chapter I looked at the downloaded "structure so far" and he had completely changed the testing directory structure to divide things into categories of test...
Is there any seasoned TDD hand out there who has, at least in the past, found this to be a source of dilemma? If so, how have you resolved it?
As a practical example, I'm cutting my teeth on TDD techniques by developing a Lucene index app: it indexes documents and then lets you query them. At the current time all the app classes are in the same package. The only method which actually needs to be public is main in one class. And yet, of course, I have many, many public methods: they could all be package-private were it not for the fact that I am using TDD.
PS no tag for "method-visibility" so I chose "class-visibility"
later
It appears that I may have been led down a rather unfortunate path by the approach taken in "Growing Object-Oriented...", where the over-use of public methods was presumably used just because it's a demonstration of the technique. Ha.
If you want to split your categories of tests, does anyone ever use this sort of approach:
\src\unit_tests\java\core\MainTest.java
but also, for example:
\src\func_tests\java\core\MainTest.javaand
\src\e2e_tests\java\core\MainTest.java?
as tests can be made to run as part of the package being tested
This does not mean that you have to put your tests in the same directory as main classes, they just have to be in the same package which can very well be separate directory.
Assume you have a package com.acme.foo. So your directory structure may be:
src
main
java
com
acme
foo
MainClass
test
java
com
acme
foo
MainClassTest
MainClassTest is in the same package as MainClass so it has access to package-private stuff. But these are separate directories, so your resulting JAR will not contain MainClassTest.
I am not sure how this works in Gradle, as I am using Maven, but I imagine the concepts there are similar. Therefore I will explain it with Maven in mind.
The typical setup in a Maven project looks like this:
On the root level of the projects there is src and target. Into the target folder everything goes that is created during the build process. This means that src contains the sources of our actual project. Under src there are two other directories: main and test. Simply put into main goes everything that will end up in the productive code, that will be delivered. The test directory contains the test code for the main tree.
Therefore it is usual that the same package hierarchy from the src/main/java directory is also present in src/test/java and therefore for a test class with the same package definition will have access to all members of the producive class which resides in the main branch.
We are considering to use Cucumber on our project for acceptance testing.
When we write a scenario in a Cucumber feature, we write a list of Given, When and Then statements.
As we use cucumber-jvm project, the Given, When and Then statement are related to Java methods in (JUnit) classes.
I want to know what is the best organization for the code related to Given / When / Then in the project structure. My main concern is the maintenance of the cucumber tests on a big project, where the number of scenario is quite important, and especially regarding the items that are shared between features.
I can see at least 2 main approaches:
Each feature is related to it's own JUnit class. So if I have a foo/bar/baz.feature cucumber file, I will find the releated foo.bar.Baz JUnit class with the adequate #Given, #When and #Then annotated methods.
Separate #Given, #When and #Then methods into "thematic" classes and packages. For example, if in my cucumber scenario I have a statement Given user "foo" is logged, then the #Given("^user \"([^\"]*)\" is logged$") annotated method will be located in the foo.user.User class method, but potentially, the #When method used later in the same cucumber scenario will be in a different Java class and package (let say foo.car.RentCar).
For me, the first approach seems good in the way that I can easily do the relation between my cucumber features and my Java code. But the drawback is that I can have a lot of redundancies or code duplication. Also, it may be hard to find a possible existing #Given method, to avoid to recreate it (the IDE can help, but here we are using Eclipse, and it does not seem to give a list of existing Given statement?).
The other approach seems better essentially when you have Given conditions shared among several cucumber feature, and thus I want to avoid code duplication. The drawback here is that it can be hard to make the link between the #Given Java method and the Given cucumber statement (maybe, again, the IDE can help?).
I'm quite new to cucumber, so maybe that my question is not a good question, and with time and experience, the structure will be self-evident, but I want to get good feedbacks on its usage...
Thanks.
I would suggest grouping your code according to the objects it refers to, similar to option #2 you presented in your question. The reasons being:
Structuring your code based on how and where it's being used is a big no-no. It's actually creating coupling between your feature files and your code.
Imagine such a thing in your product's code- the SendEmail() function wouldn't be in a class called NewEmailScreenCommands, would it? It would be in EmailActions or some such.
So the same applies here; structure your code according to what it does, and not who uses it.
The first approach would make it difficult to re-organize your feature files; You'd have to change your code files whenever you change your feature files.
Keeping code grouped by theme makes DRYing it much easier; you know exactly where all the code dealing with the user entity is, so it's easier for you to reuse it.
On our project we use that approach (i.e BlogPostStepDefinitions class), with further separating the code, if the class gets too large, to types of steps (i.e BlogPostGivenStepDefinitions).
We have also started using Cucumber-JVM for acceptance testing and have similar problems with organising code. We have opted to have 1 step definition class for each feature. At the moment this is fine as the features we are testing aren't very complex and quite separate, there is very little overlap in our features.
The second approach you mentioned would be better I think, but it is often challenging to tie together several different step definition classes for a single scenario. I think the best project structure will become clearer once you start adding more features and refactor as normal.
In the meantime here is an Eclipse plugin for cucumber,
https://github.com/matthewpietal/Eclipse-Plugin-for-Cucumber
it has syntax highlighting as well as a list of existing available steps when writing a feature.
On the current project I am taking part in, we asked ourselves the very same question.
After fiddling a bit with the possibilities, what we opted for was a mix of both the solutions you exposed.
Have steps regrouped in theme-centric common steps classes
app-start steps
security check steps
[place random feature concern here] steps
And classes of scenario (and in some case even feature) specific steps
This was to have at the same time the grouping of factorized code which is pretty easily identifiable on it's whatabouts, whereabouts and whatnot.
Yet it allows not to clutter those common classes with overly specific code.
The wiring between all these classes is handled by spring (with cucumber spring which does a great job once you get the hang of it).
I've got 2 questions about organising Unit tests.
Do I have to put test to the same package as tested class, or can I organise tests in different packages?
For example if I have validity and other tests, is it correct to split them into different packages, even if they are for same class?
What about mock and stub classes? Shall I separate them from packages containing only tests, or put them together?
The way we do our JUnit test cases is to put them in the same package, but in a different root directory. Since we use Maven, we just use the standard locations making the structure similar to the following.
src/main/java/com/foo/Bar.java
src/test/java/com/foo/BarTest.java
Obviously there's more to the structure, but this lets us build the tests separately from the mainline code, but still access protected classes and the like. With respect to different types of tests, this is very subjective. When we started our testing effort (which unfortunately started after development), I tried to keep things pretty isolated. Unfortunately, it quickly became a nightmare when we got to the 500+ test case point. I've since tried to do more consolidation. This led to reduced amounts of code to maintain. As I said, though, it's very subjective.
As far as test-only code, we keep it in a separate com.foo.test package that resides only in the src/test/java tree.
I too tend to put my tests in the same package but under a different root directory. This allows me to test package-private classes or access packing-private classes while testing something else in the package. They are kept in a separate directory tree to allow excluding them from the deployed result (in particular to ensure that test code didn't accidentally get into production code). What matters most, however, is what works for your situation.
In terms of how many test classes per production class, the theory I've seen is that you write one test class per fixture, that is per setup structure. In many cases that is the same (or close enough) to one test class per production class, but I have sometimes written more test classes (in particular equality tests tend to be separated) for a give production class, and occasionally one test class of for a group of (related) production classes (say, for testing the Strategy pattern).
Mostly, I don't worry too much about the theory, but rework the tests as needed to keep duplication to an absolute minimum.
Keeping it the same package allows you to use package-private visibility for code that is intended to be accessed via the test only.
Regarding using separate root directories, that is a good practice. It also has an advantage for us, since we use IDEA, IDEA recognizes that production code cannot reference test code.
In terms of keeping them separate, there is a great power in having one, and only one, test class per production class at the unit level. Of course, some classes get created in production as part of refactoring that have no test classes at all, and that is fine, but when you want to know what test tests a certain class, having a convention that says ClassNameTest is the tests for ClassName is very helpful.
TestNG is much friendlier to this paradigm than JUnit, though.
Test classes should be rather in different packages, it's easier to separate them from the production code when you package it for release. I usually keep lots of test fluff in those packages, all sorts of mocks, configurations, scenarios.. But when you build - it doesn't get it. In some situations, it's a good idea to keep your testing stuff even in different projects. Depends.