Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Testing against interfaces instead of implementations #205

Open
dstango opened this issue Dec 17, 2023 · 2 comments
Open

Support Testing against interfaces instead of implementations #205

dstango opened this issue Dec 17, 2023 · 2 comments

Comments

@dstango
Copy link
Contributor

dstango commented Dec 17, 2023

Currently MoreUnit matches implementing classes and corresponding tests.

It doesn't work if you want to test against an interface, e.g. if you have a setup like a client of mine with Arquillian and dependency injection into interface-typed properties.

Consider a setup like the following three types:

public interface Foo {
	int bar();
}

public class FooImpl implements Foo {
	@Override
	public int bar() {
		return 0;
	}
}

public class FooTest  {
	@Test
	void testBar() throws Exception {
		Foo foo = new FooImpl();
		Assertions.assertEquals(foo.bar(), 1);
	}
}

MoreUnit will:

  • jump from Foo to FooTest (correct),
  • jump from FooTest to Foo (undesired),
  • not jump anywhere from FooImpl, but propose to create a new test class (undesired).

If the test class is named FooImplTest, MoreUnit will

  • not jump anywhere from Foo, but propose to create a new test class (undesired),
  • jump from FooImpl to FooImplTest (correct),
  • jump from FooImplTest to Foo (undesired).

I propose to change the behaviour in such situations like the following:
MoreUnit will

  • jump from Foo to FooTest,
  • jump from FooTest to FooImpl,
  • jump from FooImpl to FooTest,
  • if the test class is named FooImplTest, the equivalent behaviour should occur.

Nice to have:

  • if there are several implementations of the interface available, jump to the concrete implementation used, if it can be determined directly/easily,
  • if such a definite resolution cannot be made, offer a selection of target classes.

I'm not sure how best to implement this yet, and would be happy to get some ideas. Two ideas popping my head (without checking the source code for feasibility yet) are either to have a special naming pattern matching in settings to find the right class, or to identify if a type is an interface, and then change the logic of the jumping accordingly.

Any more ideas/suggestions?

@Bananeweizen
Copy link
Contributor

Cannot reproduce. MoreUnit jumps perfectly between the implementation and test, if the test is called FooImplTest and default settings are used.

Generally speaking your suggestion is bad IMO. It's overly complex and cannot be generalized to a good and simple to understand rule for every Java project and Java developer out there. In my eyes your current test name is just lying, because the test doesn't test anything of the interface, but just its subclass implementation. If you want to "unify" the interface and implementation for easier navigation, then make the implementation a default implementation of the interface, or make the implementation a nested class of the interface, or... but don't try to bend the unit testing. There is nothing to test in an interface without default implementations.

@dstango
Copy link
Contributor Author

dstango commented Dec 22, 2023

@Bananeweizen did you try all mentioned cases? At least jumping from FooImplTest to Foo should occur, as long as the type of foo in the test is Foo and not FooImpl.

Of course I was fearing you might find it a bad idea, as the general approach is issue of debates, like here: https://stackoverflow.com/questions/6724401/how-to-write-junit-tests-for-interfaces ... ;-)

Anyhow: that's why I was mentioning the Arquillian setup I encountered in a lot of projects of a client of mine: they rely heavily on dependency injection in a maven multi module project, and they use interfaces for integration tests, in which concrete implementations from another module get injected into the Arquillian test. Plus: in such a situation you only want to focus the tests on the interface, not any implementation details. And default methods are out of the question, too, as the interfaces are generated code.

You might dislike the whole architectural setup of these projects, but that's nothing I can change.
I was simply in a situation where I wanted to praise the benefits of MoreUnit, only to notice when showing it, that the benefits vanished, as I couldn't even easily jump between the test (against the interfaces) and the implementation. :-(

One thing I don't quite understand:

It's overly complex and cannot be generalized to a good and simple to understand rule for every Java project and Java developer out there.

The implementation might be somewhat complex, but what's not simple in a rule that says: "Ctrl-J jumps between test and implementation(s)."
Edge cases: If several tests are found, a selection is presented (already existing). If several implementations are found, a selection is presented (that would be new).

But I'm happy to discuss this further, hopefully it'll generate some more insights.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants