Behaviour Driven Development is one of the most useful approaches to write high level tests that are understandable and even writable by anybody who has necessary domain knowledge.
In my favourite syntax, Gherkin, a test would look like:
Feature: Hungry Cat Behaviour Scenario: Given I am a cat And I have not eaten anything in the last 30 mins When I see a spider And the spider is reachable Then I pounce on it And I eat it
Then I would write my glue code in Cucumber and generate reports. However, designing a good step vocabulary and glue code is a skill one can hone by making mistakes over and over.
Having worked on telecom solutions that require automated validation of quite wide range of high level acceptance scenarios; one of the biggest tempting mistake I see (and I did sometimes) is tapping in to something internal to the application for seemingly benign reasons, because it is way too easy.
You may want to just use an internal data structure, some internal function, a bean, a resource to quickly achieve certain things in your test side.
Is that a bad practice ? Definitely. No excuse.
A BDD test that is used to verify high level functionality should be written against a black box, without relying on any internal knowledge of the software. Otherwise we introduce a dangerous coupling between the external test code and the production code.
It is very easy to close the eyes and just make the next mistake by accepting it as a technical debt to solve later. Because you really have to finish that work soon and without a proper test case, there can not be any real proof of Done
What if we write the BDD tests in a different programming language ?
For example, writing the product in Java/C#/Scala etc but BDD tests in Python.
It is highly likely that this idea has already been visited. Nevertheless I find it worthy to consider it seriously.
What Do We Gain ?
We effectively cut any possibility to quickly consume an internal structure,break the walls and leak abstractions.
It forces us to think completely outside of the product and rely only on contracts.
It helps us discovering usability/observability issues.
In some cases, we can gain speed.
In some cases, we can spend less effort on the test code while achieving the same outcome.
Obviously this is far from being a rule of thumb or best practice. However, it worths considering if the project in our hands looks like a fit for this usage.