📜 ⬆️ ⬇️

The evolution of automatic testing in 1C: Enterprise

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:

image

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:
// { Plugin interface  ()   =  ; .("", .); .("", ().); .("", ().);   ();  // } Plugin interface 

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?”.

image

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:

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:

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:
  1. The user selects the Loader, which he wants to use;
  2. 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;
  3. A test path is searched for the selected path;
  4. 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;
  5. 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:

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 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.

Source: https://habr.com/ru/post/270061/


All Articles