Before the release of the new version of the xUnitFor1C testing framework, quite a bit remains, which means it's time to tell about the work done and what the users expect.
The release will turn out really major, there are a lot of changes, and they are global. But first things first.
Why all the sawing?
As far as I understand, at the time when the project was just born, the main goal was to understand how unit testing could be in demand in 1C environment. It is clear that to think over and select the levels of abstractions at the stage of prototyping is not very promising. The prototype does not have the elasticity of this code. A prototype is an experiment whose results need to be thrown away.
')
Then the development flag passed from one enthusiast to another, while the basic architecture remained the same. With the increasing popularity of the product and the realization that I would like to receive, it has become increasingly difficult to make changes.
I like Alan Cooper's metaphor:
Creating a large program can be compared to building a brick column. This pillar consists of a thousand bricks laid one upon another. A pillar can be built only if bricks are laid with great precision. Any deviation will cause the bricks to fall. If the brick with the number 998 can deflect by five millimeters, the pillar will probably be able to withstand a thousand bricks, but if the deviation is on the 5th brick, the pillar will never be higher than three dozen.
The architecture that existed from the prototype was a deviation on the 5th brick, which did not allow us to add the new functionality that we wanted so much - testing in the BDD style, in particular, the use of Gherkin. There is an opinion that you need to choose one thing. Either TDD or BDD. Having worked on the principles of flexible testing, I realized that modular and scenario tests should not be opposed in any way, they are an excellent complement to each other!
Here is the flexible testing matrix:

Unit tests refer to quadrant 1 — low-level tests. Designed for the design of loosely coupled, flexible, tested architecture. They perform for the developer the same role as the climber safety cable. At the same time, they are quite cheap in development and maintenance.
Scenario tests refer to quadrant 2 — higher level tests. We need to make sure that we correctly understand what needs to be done. This is a bridge between business and development, the ability to speak the same language. Excellent documentation that will never become obsolete. However, they are more expensive to build and more fragile.
For me, so wonderful synergy. I believe that to create high-quality software you need to use both approaches together! Combined tests of both types provide excellent protection against regression.
I’ll run a little ahead and say that the BDD-style testing has not yet been implemented on the new engine, but the foundation has been fully prepared. Scenario testing is the next step.
Architecture
It is completely redesigned. The tool has become much more flexible and easier to develop. Now this is not processing with 8.5k lines of code, now it is the core with the plugin system. Yes, there is no error, in 1C you can make a framework that will be expanded with plugins.
External processing, located in the “Plugins” folder and implementing the following basic interface, act as plug-ins:
The appeal to the plugin is by identifier, for example:
= .("");
The kernel can now be roughly expressed as a single function:
= ();
A reasonable question arises: “What kind of canonical test tree and test result?”.

The canonical test tree allows us to build a universal “launch” of test methods. It is a tree data structure. It consists of nodes of the following types:
- container - serves for grouping purposes and may have subordinate nodes. Also for the container, you can specify the processing mode of the child nodes:
- random order traversal - needed for unit tests, guarantees the independence of the tests from each other and allows you to find any side effects;
- strict bypass order - needed for scenario tests, all child nodes will be processed in a strict order. In addition, containers of this type have the “context” property, which has child elements for read and write access.
- element is essentially test method metadata that allows you to create a context and call a test method. It has the following basic properties:
- Path - a string that allows you to create an instance of the object, which you can call a test method;
- MethodName - the actual name of the test method to be executed;
- Parameters - an array of parameters passed to the test method. The number and types of parameters must match the signature of the test method. Required for parameterized tests.
The canonical test result is very similar to the test tree with the difference that it contains additional information about the results of the execution:
- For containers:
- The state is the result of the aggregation of the states of the child nodes;
- Statistics - the total number of tests in the container, the number of broken tests, the number of unrealized tests, the total execution time in ms.
- For items:
- Condition - not executed / passed / not implemented / broken;
- Lead time;
- Message - contains the exception text if the test is broken.
Where do canonical trees come from with tests and how does this contribute to universalization?
Building a tree with tests deals with a special type of plug-in “Loader”. Typical scenario of working with loaders:
- The user selects the Loader, which he wants to use;
- Next, the path to search for test scripts is determined (possibly interactive). In this case, the path is just a certain string that the selected loader can correctly interpret. For example, it can be a file system path or a path in the configuration metadata tree or ... anything;
- A test path is searched for the selected path;
- According to the found scenarios, a test tree for the kernel is formed, while in the paths at the leaves of the tree some lines are indicated (similar to paragraph 2) that the selected loader can correctly interpret;
- When tests are being performed, the kernel will contact the appropriate loader to resolve paths on the leaves of the tree.
Loader API:
The function Select PathInteractively (Current Path = "") is a client method for interactively choosing a path for loading tests;
The Load function (Context-Core, Path) - search for test scenarios and building the canonical test tree;
The function GetContextPo Path (ContextNucleus, Path) - receiving test context on the transmitted path.
Currently, 3 basic loaders are implemented:
- File Loader - unit test loader from epf files. It uses file system paths as paths;
- Directory Loader - built on top of the file uploader. As a path to search takes the path to the directory of the file system. For the rest, relies entirely on the file uploader;
- Loader From Subsystem Configurations - uses the configuration metadata tree as a string representation as paths. For example, “Metadata. Processing. Test_ Processing.” The test processing API borrows a file downloader.
In the near future, the creation of a BDD Downloader that will work with the Gherkin feature files.
And what to do with the canonical test results?
After the kernel has processed the test tree into the test result, it passes it to another special type of the Report Generator plugin.
Report generators transform canonical test results into any other representation. For example, now implemented:
- Report Generator MXL - moxel-format of the report, which is now used in interactive work with the tool;
- Report GeneratorJUnitXML is a junit.xml report that is used in continuous integration (CI).
Report Generator API:
The Create Report function (Context Core, Test Results) - generation of a report in the format proposed by the plugin. Test results are passed to the plugin in canonical for the kernel format;
The Show (Report) procedure is a client method for interactively displaying a generated report. The plug-in itself determines exactly how the report generated by it should be issued to the user;
Export Procedure (Report, Full Path of the File) - saves the report on the specified path, mainly used for CI purposes.
Goodies
All sorts of "useful" have a type of plug-in "Utility". As a rule, perform a library or service function. For example, a library of statements in the style of BDD is a plugin called “BDD statements”, which I wrote about in my last article. “Serializer MXL” is a service plugin that serializes database data into moxel-format and back.
Afterword
Before the mainstream development, the source code is available by
reference .
Now it can be argued that the framework has grown from “just a unit testing tool” to “a tool that allows you to cover almost all possible types of automatic testing”. It is modular, clearly divided into layers, can be easily refined and expanded. It seems the current name has ceased to transmit the purpose of the product. Maybe it's time to change the name? If you have a good idea for a title, feel free to share.