{"id":23762403,"url":"https://github.com/thymeleaf/thymeleaf-testing","last_synced_at":"2025-09-05T06:31:52.779Z","repository":{"id":6169956,"uuid":"7399780","full_name":"thymeleaf/thymeleaf-testing","owner":"thymeleaf","description":"Thymeleaf testing infrastructure","archived":false,"fork":false,"pushed_at":"2022-07-07T19:47:56.000Z","size":1441,"stargazers_count":77,"open_issues_count":25,"forks_count":27,"subscribers_count":11,"default_branch":"3.1-master","last_synced_at":"2025-04-06T00:51:07.668Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thymeleaf.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":"CONTRIBUTING.markdown","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-01-01T22:46:17.000Z","updated_at":"2024-04-24T09:40:16.000Z","dependencies_parsed_at":"2022-07-12T15:03:05.284Z","dependency_job_id":null,"html_url":"https://github.com/thymeleaf/thymeleaf-testing","commit_stats":null,"previous_names":[],"tags_count":61,"template":false,"template_full_name":null,"purl":"pkg:github/thymeleaf/thymeleaf-testing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thymeleaf%2Fthymeleaf-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thymeleaf%2Fthymeleaf-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thymeleaf%2Fthymeleaf-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thymeleaf%2Fthymeleaf-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thymeleaf","download_url":"https://codeload.github.com/thymeleaf/thymeleaf-testing/tar.gz/refs/heads/3.1-master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thymeleaf%2Fthymeleaf-testing/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273722729,"owners_count":25156300,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-31T21:19:11.000Z","updated_at":"2025-09-05T06:31:52.150Z","avatar_url":"https://github.com/thymeleaf.png","language":"Java","readme":"\nThymeleaf Testing Library\n=========================\n\n-------------------------------------------------------------\n\n**[Please make sure to select the branch corresponding to the version of Thymeleaf you are using]**\n\n\nStatus\n------\n\nThis is an auxiliary testing library, not directly a part of the Thymeleaf core but part of the project, developed and supported by the [Thymeleaf Team](http://www.thymeleaf.org/team.html).\n\nCurrent versions:\n\n  * **3.0.4.RELEASE** - for Thymeleaf 3.0 (requires 3.0.4+)\n  * **2.1.4.RELEASE** - for Thymeleaf 2.1 (requires 2.1.2+)\n\n\nLicense\n-------\n\nThis software is licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).\n\n\nRequirements (3.0.x)\n--------------------\n\n  *   Thymeleaf **3.0.4+**\n  *   Attoparser **2.0.3.RELEASE+**\n\n\nMaven info\n----------\n\n  *   groupId: `org.thymeleaf`\n  *   artifactId: `thymeleaf-testing`\n\n\nFeatures\n--------\n\n  *   Works as an independent library, **callable from multiple testing frameworks** like e.g. JUnit.\n  *   **Tests only the view layer**: template processing and its result.\n  *   Includes **benchmarking** facilities: all tests are timed, times are aggregated.\n  *   Highly extensible and configurable\n  *   Versatile testing artifacts: test sequences, iteration, concurrent execution...\n  *   Based on interfaces. Out-of-the-box *standard test resolution* allows:\n      * Easy specification of tests as simple text files, sequences as folders.\n\t  * Advanced test configuration.\n\t  * Test inheritance.\n\t  * *Lenient* result matching, ignoring excess unneeded whitespace etc.\n  * **Spring Framework** and **Spring Security** integration.\n\n------------------------------------------------------------------------------\n\n\n## Usage ##\n\nThe testing framework can be used with just two lines of code:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"classpath:test\");\n```\n\nNote how here we are only specifying the name of the *testable* to be resolved: `\"classpath:test\"`, which is a folder called `test` in classpath. (more on testables later). But anyway this is only two lines, and therefore we are accepting some defaults, namely:\n\n   * Dialects. By default only the *Standard Dialect* will be enabled.\n   * Resolvers. By default the *standard test resolution* mechanism will be used (more on it later).\n   * Reporters. By default a console reporter will be used.\n\nLet's see the whole `TestExecutor` configuration process:\n\n```java\nfinal List\u003cIDialect\u003e dialects = ...\nfinal ITestableResolver resolver = ...\nfinal ITestReporter reporter = ...\n\nfinal TestExecutor executor = new TestExecutor();\nexecutor.setDialects(dialects);\nexecutor.setTestableResolver(resolver);\nexecutor.setReporter(reporter);\nexecutor.execute(\"classpath:test\");\n```\n\nThe meaning and working of the *dialects* property is pretty obvious and straightforward. As for the *resolvers* and *reporters*, we will see more on them in next sections.\n\n## API ##\n\nThe Thymeleaf testing framework is based on interfaces, and therefore defines an API that specifies the diverse artifacts involved in the testing process:\n\nTest artifacts at the `org.thymeleaf.testing.templateengine.testable` package:\n\n| Interface                  | Description |Base Impl| Default Impl|\n|----------------------------|-------------|------------------|-------------|\n|`ITestable`                 | Implemented by objects designed for being *tested*, be it a simple test or an aggregating structure of any kind. Every other interface in this package extends this one. | `AbstractTestable` | |\n|`ITest`                 | Represents tests, the basic unit for testing and simplest `ITestable` implementation. Tests are in charge not only of containing test data, but also of evaluating/checking test results. | `AbstractTest` | `Test` |\n|`ITestSequence`                 | Represents sequences of tests, test structures or any combination of theses (sequences of objects implementing the `ITestable` interface). |  | `TestSequence` |\n|`ITestIterator`                 | Represents objects capable of iterating (executing a number of times) other test structures. |  | `TestIterator` |\n|`ITestParallelizer`                 | Represents objects capable of using several threads for executing the same test structure in each thread, concurrently. |  | `TestParallelizer` |\n|`ITestResult`                 | Represents the results of executing a test and evaluating its results. |  | `TestResult` |\n\n\nInterfaces at the `org.thymeleaf.testing.templateengine.resolver` package:\n\n| Interface                  | Description |\n|----------------------------|-------------|\n|`ITestableResolver`         | Implemented by objects in charge of *resolving testables*, this is, of creating the `ITestable` objects and structures that will be executed. A *standard test resolution* implementation is provided out of the box that builds these testable structures from text files and their containing folders in disk. |\n\n\nInterfaces at the `org.thymeleaf.testing.templateengine.resource` package:\n\n| Interface                  | Description |\n|----------------------------|-------------|\n|`ITestResource`             | Implemented by objects representing test resources like testable artifact locations, test input text, test output text, etc. |\n|`ITestResourceResolver`     | Implemented by objects in charge of resolving test resources, used by *testable resolvers*. For example, a *testable resolver* (`ITestableResolver`) will use an `ITestResourceResolver` implementation for converting the resource name `\"classpath:test\"` into a valid `ITestResource` object. |\n\n\nInterfaces at the `org.thymeleaf.testing.templateengine.report` package:\n\n| Interface                  | Description |\n|----------------------------|-------------|\n|`ITestReporter`             | Implemented by objects in charge of reporting the results of executing tests, sequences, etc. along with their associated execution times. |\n\n\nInterfaces at the `org.thymeleaf.testing.templateengine.context` package:\n\n| Interface                  | Description |\n|----------------------------|-------------|\n|`ITestContext`              | Implemented by objects representing the context (variables, locale, etc.) to be used for executing tests. |\n|`IProcessingContextBuilder` | Implemented by objects in charge of creating the `IContext` to be used for test excecution from the resolved `ITestContext`. |\n\n\nInterfaces at the `org.thymeleaf.testing.templateengine.messages` package:\n\n| Interface                  | Description |\n|----------------------------|-------------|\n|`ITestMessages`             | Implemented by objects representing the set of externalized (or *internationalized*) messages to be used for executing tests. |\n\n\nIn addition to these interfaces, this testing API also includes the `org.thymeleaf.testing.templateengine.engine.TestExecutor` class, in charge of executing the test structures.\n\n\n## Test Reporters ##\n\nTest Reporters implement the `org.thymeleaf.testing.templateengine.report.ITestReporter` interface and allow the engine to report when a test has been executed, the execution result, and also the execution time (aggregated in the case of a structure).\n\nOut of the box, thymeleaf-testing provides two implementations at the `org.thymeleaf.testing.templateengine.report` package:\n   * `AbstractTextualTestReporter`, an abstract text-based implementation suitable for easily creating reporters that output text.\n   * `ConsoleTestReporter`, extending the former, which writes these *text report items* to the console.\n\nConsole reporting looks like this:\n\n```\n[2013-04-19 02:23:29][KE1OMC][main] [sequence:start][maintests]\n[2013-04-19 02:23:29][KE1OMC][main]   [test:end][text.test][175729614][OK] Test executed OK.  Time: 175729614ns (175ms).\n[2013-04-19 02:23:29][KE1OMC][main]   [test:end][utext.test][3365839][OK] Test executed OK.  Time: 3365839ns (3ms).\n[2013-04-19 02:23:29][KE1OMC][main] [sequence:end][maintests][2][2][179095453] Tests OK: 2 of 2. Sequence executed in 179095453ns (179ms)\n```\n\n\nIt's easy to create new reporters that could write test results to different formats like CSV, Excel, etc. or even write results to a database.\n\n\n### Integrating with JUnit ###\n\nThe easiest way to integrate with JUnit is to use JUnit tests to launch sets of tests, using afterwards JUnit's assertion mechanism to check results:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"mytestset\");\nAssert.assertTrue(executor.getReporter().isAllOK());\n```\n\n...or the equivalent, more convenient:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"mytestset\");\nAssert.assertTrue(executor.isAllOK());\n```\n\nNote that this *test set* can be a single test:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"mytestset/onetest.thtest\");\nAssert.assertTrue(executor.isAllOK());\n```\n\nYou can reuse your test executor by resetting its reporter after each execution:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"mytestset/onetest.thtest\");\nAssert.assertTrue(executor.isAllOK());\nexecutor.getReporter().reset();\n```\n\n...or the equivalent, more convenient:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\nexecutor.execute(\"mytestset/onetest.thtest\");\nAssert.assertTrue(executor.isAllOK());\nexecutor.reset();\n```\n\nSo you can use your executor for executing several *test sets* (or single tests) in the same JUnit test method:\n\n```java\nfinal TestExecutor executor = new TestExecutor();\n...\nexecutor.execute(\"mytestset/onetest.thtest\");\nAssert.assertTrue(executor.isAllOK());\nexecutor.reset();\n...\nexecutor.execute(\"mytestset/twotest.thtest\");\nAssert.assertTrue(executor.isAllOK());\nexecutor.reset();\n...\nexecutor.execute(\"anothertestset\");\nAssert.assertTrue(executor.isAllOK());\nexecutor.reset();\n```\n\nNote that each execution of `executor.execute(...)` will create its own `TemplateEngine` instance and resolvers, an so no templates will be cached from one execution to the next.\n\n\n## Testable Resolvers ##\n\nStandard test resolution is provided by means of an implementation of the `org.thymeleaf.testing.templateengine.resolver.ITestableResolver` interface called `org.thymeleaf.testing.templateengine.resolver.StandardTestableResolver`.\n\n\n### The Standard Resolution mechanism ###\n\nThe standard test resolution mechanism works like this:\n\n   * Tests are specified in text files, following a specific directive-based format.\n   * Folders can be used for grouping tests into sequences, iterators or parallelizers.\n   * Test ordering and sequencing can be configured through the use of *index files*.\n\nLet's see each topic separately.\n\n\n#### Test file format ####\n\nA test file is a text file with a name ending in `.thtest` It can look like this:\n\n```\n%TEMPLATE_MODE HTML5\n# ------------ separator comment -----------\n%CONTEXT\nonevar = 'Goodbye,'\n# ------------------------------------------\n%MESSAGES\none.msg = Crisis\n# ------------------------------------------\n%INPUT\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003cbody\u003e\n      \u003cspan th:text=\"${onevar}\"\u003eHello,\u003c/span\u003e\n      \u003cspan th:text=\"#{one.msg}\"\u003eWorld!\u003c/span\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n# ------------------------------------------\n%OUTPUT \n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003cbody\u003e\n      \u003cspan\u003eGoodbye,\u003c/span\u003e\n      \u003cspan\u003eCrisis\u003c/span\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nWe can see there that tests are configured by means of *directives*, and that these directives are specified in the form of `%DIRECTIVENAME`. The available directives are:\n\n*Test Configuration:*\n\n| Name                       | Description |\n|----------------------------|-------------|\n|`%NAME`                     | Name of the test, in order to make it identifiable in reports/logs. This is *optional*. If not specified, the file name will be used as test name. |\n|`%CONTEXT`                  | Context variables to be made available to the tested template. These variables should be specified in the form of *properties* (same syntax as Java `.properties` files), and **property values are parsed and executed as OGNL expressions**. Specifying context variables is *optional* and they can be inherited from parent tests.\u003cbr /\u003eYou can read more about the specification of context variables below.|\n|`%MESSAGES`                 | Default (no locale-specific) externalized/internationalized messages to be made available to the tested template. These variables should be specified in the form of *properties* (same syntax as Java `.properties` files). Specifying messages is *optional* and they can be inherited from parent tests. |\n|`%MESSAGES[es]`             | Same as `%MESSAGES`, but specifying messages for a specific locale: `es`, `en_US`, `gl_ES`, etc. |\n\n*Test input:*\n\n| Name                       | Description |\n|----------------------------|-------------|\n|`%INPUT`                    | Test input, in the form of an HTML template or fragment. A resource name can also be specified between parenthesis, like `%INPUT (file:/home/user/myproject/src/main/resources/templates/mytemplate.html)`. This parameter is *required*. |\n|`%INPUT[qualif]`            | Additional inputs can be specified by adding a *qualifier* to its name. These additional inputs can be used as external template fragments in `th:include=\"qualif\"`, `th:substituteby=\"qualif :: frag\"`, etc. |\n|`%FRAGMENT`                 | Fragment specification (in the same format as used in `th:include` attributes) to be applied on the test input before processing. *Optional*. |\n|`%TEMPLATE_MODE`            | Template mode to be used: `HTML5`, `XHTML`, etc. |\n|`%TEMPLATE_MODE[qualif]`    | Additional template modes can be specified for additional inputs (matching those specified with `%INPUT[qualif]`. |\n|`%CACHE`                    | Whether template cache should be `on` or `off`. If cache is *on*, the input for this test will be parsed only the first time it is processed.|\n\n*Test expected output:*\n\n| Name                       | Description |\n|----------------------------|-------------|\n|`%OUTPUT`                   | Test output to be expected, if we expect template execution to finish successfully. Either this or the `%EXCEPTION` directive must be specified. A resource name can also be specified between parenthesis, like `%OUTPUT (file:/home/user/myproject/src/test/resources/results/mytemplate-res.html)` |\n|`%EXACT_MATCH`              | Whether *exact matching* should be used. By default, *lenient matching* is used, which means excess whitespace (*ignorable whitespace*) will not be taken into account for matching test results. Setting this flag to `true` will perform exact *character-by-character* matching. |\n|`%EXCEPTION`                | Exception to be expected, if we expect template execution to raise an exception. Either this or the `%OUTPUT` directive must be specified.  |\n|`%EXCEPTION_MESSAGE_PATTERN`| Pattern (in `java.util.regex.Pattern` syntax) expected to match the message of the exception raised during template execution. This directive needs the `%EXCEPTION` directive to be specified too. |\n\n*Inheritance:*\n\n| Name                       | Description |\n|----------------------------|-------------|\n|`%EXTENDS`                  | Test specification (in a format understandable by the implementations of `ITestableResolver` and `ITestResourceResolver` being used) from which this test must inherit all its directives, overriding only those that are explicitly specified in the current test along with this `%EXTENDS` directive.\u003cbr /\u003eExamples: `%EXTENDS classpath:test/bases/base1.test` |\n\nAlso, any line starting by `#` in a test file will be considered **a comment** and simply ignored.\n\n\n##### More on resource resolution #####\n\nThe standard mechanism for resource resolution allows you to:\n\n   * Specify resources in classpath: `classpath:tests/mytest.thtest`\n   * Specify resources in the filesystem: `file:/home/myuser/tests/mytest.thtest` or `file:C\\Users\\myser\\tests\\mytest.thtest`.\n\nAlso, in some scenarios (like the `%EXTENDS` directive in test files) resource resolution can be relative to the current resource:\n\n```\n%EXTENDS ../../base-tests/base.thtest\n```\n\nNote that, when using resource resolution in an `%INPUT` or `%OUTPUT` directive, resource names must be specified between parenthesis:\n\n```\n%INPUT (file:/home/user/myproject/src/main/resources/templates/mytemplate.html)\n```\n\n##### More on context specification #####\n\nAs already said, context is specified like:\n\n```properties\n%CONTEXT\nonevar = 'Goodbye!'\ntwovar = 'Hello!'\n```\n\nAnd those literals are specified between commas because all context values are in fact **OGNL** expressions, so we could in fact use previous variables in new ones:\n\n```properties\n%CONTEXT\nonevar = 'Hello, '\ntwovar = onevar + 'World!'\n```\n\nWe can also create objects, and set its properties:\n\n```properties\n%CONTEXT\nuser = new com.myapp.User()\nuser.firstName = 'John'\nuser.lastName = 'Apricot'\n```\n\nAlso maps:\n\n```properties\n%CONTEXT\nuser = #{ 'firstName' : 'John', 'lastName' : 'Apricot' }\n```\n\nWe can set request parameters (multivalued), request attributes, session attributes and servlet context attributes using the `param`, `request`, `session` and `application` prefixes:\n\n```properties\n%CONTEXT\nsession.userLogin = 'japricot'\nparam.selection = 'admin'\nparam.selection = 'manager'\n```\n\nUtility objects like `#strings`, `#dates`, `#lists`, etc. can be used:\n\n```properties\n%CONTEXT\nrequest.timestamp = #calendars.createNow()\n```\n\nFinally, note that **context variables are inherited** when a test is set as an extension of another one by means of the `%EXTENDS` directive.\n\n##### Selecting locale for execution #####\n\nThe locale to be used for execution can be selected by giving value to a context variable called `locale`:\n\n```properties\n%CONTEXT\nlocale = 'gl_ES'\n```\n\n\n#### Test folder format ####\n\nThe folders that contain tests will themselves be resolved as test structures, and their names will be used to indicate the existence of *iterations* or *parallelizers*.\n\nImagine we have this folder structure at our classpath:\n\n    /tests\n     |\n     +-\u003e/warmup\n     |   |\n     |   +-\u003etestw1.thtest\n     |   |\n     |   +-\u003etestw2.thtest\n     |\n     +-\u003e/expressions-iter-10\n         |\n         +-\u003eexpression1.thtest\n         |\n         +-\u003e/expression-stress-parallel-3\n             |\n             +-\u003eexpression21.thtest\n             |\n             +-\u003eexpression22.thtest\n\nWhen we ask the standard test resolver to resolve that folder called `tests` (with `\"classpath:tests\"`), it will create the following *testable artifact* structure:\n\n   * A *Test Sequence* called `tests`, containing:\n     * A *Test Sequence* called `warmup` containing:\n       * Two tests: `testw1.thtest` and `testw2.thtest`.\n     * A *Test Iterator* called `expressions`, iterated 10 times, containing:\n       * One test: `expression1.thtest`.\n       * A *Test Parallelizer* called `expression-stress`, executed by 3 concurrent threads, containing:\n         * Two tests: `expression21.thtest` and `expression22.thtest`.\n\nSo, as can be extracted from the example above:\n\n   * In general, folders will be resolved as *test sequence*\n   * Folders with a name ending in `-iter-X` will be resolved as a *test iterator* iterating `X` times.\n   * Folders with a name ending in `-parallel-X` will be resolved as a *test parallelizer* executing its contents with `X` concurrent threads.\n\n\n#### Test index files ####\n\nIndex files are files with a name ending with `.thindex`. They allow developers to specify which tests and in which order they want to be executed, this is, in practice, create *a test sequence*. They also allow the specification of iteration or parallelization without having to change the name of a folder.\n\nExample contents for a `sample.thindex` file:\n\n```\nexp.thtest\ninclude.thtest\ntext.thtest [iter-20]\ntest2 [parallel-3]\n```\n\nAccording to the above index, the `text.thtest` file will be executed in third position, 20 times. And the `test2` folder will be considered a parallelizer, just as if it was called `test2-parallel-3` instead.\n\nAlso, note that when a folder includes a special file named `folder.thindex`, this will be considered to specify the sequence in which the folder files have to be executed, even if this `folder.thindex` file isn't explicitly called.\n\n\n### Extending the standard test resolution mechanism ###\n\nThe standard resolution mechanism can be extended in several ways, by means of a series of *setter* methods in the `StandardTestableResolver` class which allow developers to configure how each step of test resolution is performed:\n\n| Setter                       | Description |\n|----------------------------|-------------|\n|`setTestReader(IStandardTestReader)`      | Specifies the implementation that will be in charge of reading test files and return its raw data. Default implementation is the `StandardTestReader` class. |\n|`setTestEvaluator(IStandardTestEvaluator)` | Specifies the implementation that will be in charge of evaluating the *raw data* returned by the test reader into the different values that will be used for building the test object. Default implementation is `StandardTestEvaluator`. |\n|`setTestBuilder(IStandardTestBuilder)` | Specifies the implementation that will be in charge of actually building test objects from the values evaluated by the *test evaluator* in the previous step. Default implementation is `StandardTestBuilder`. |\n|`setTestResourceResolver(ITestResourceResolver)` | Specifies the implementation that will be in charge of actually resolving resources (including testable artifacts, `%EXTENDS` directives, `.thindex` entries, etc.). |\n\n\n\n## Spring integration ##\n\nIn order to execute thymeleaf tests using the **SpringStandard** dialect in its entirety, we need to activate certain Spring mechanisms that support some Spring-integrated processors included in this dialect (like `th:field`).\n\nInitialization would look like this:\n\n```java\nfinal List\u003cIDialect\u003e dialects = new ArrayList\u003cIDialect\u003e();\ndialects.add(new SpringStandardDialect());\n\nfinal SpringWebProcessingContextBuilder springPCBuilder = new SpringWebProcessingContextBuilder();\n\nfinal TestExecutor executor = new TestExecutor();\nexecutor.setProcessingContextBuilder(springPCBuilder);\nexecutor.setDialects(dialects);\n\nexecutor.execute(\"tests\");\n```\n\nPay special attention to that instantiation of `org.thymeleaf.testing.templateengine.context.web.SpringWebProcessContextBuilder`. That is the class which will activate the needed Spring mechanisms.\n\nThis Spring-based context builder will try to initialize a Spring application context from an `applicationContext.xml` file present in the classpath. The name of this file can be overridden or even set to `null` if we do not wish to initialize any beans:\n\n```java\nfinal IProcessingContextBuilder springPCBuilder = new SpringWebProcessingContextBuilder();\nspringPCBuilder.setApplicationContextConfigLocation(\"classpath:springConfig/spring.xml\");\n```\n\n### Model binding ###\n\nIf we want to test a page including bound model objects like, for example, a *form-backing bean* (or *command*), we just have to declare and initialize it:\n\n```properties\n%CONTEXT\nuser = new my.company.User()\nuser.name = 'John'\nuser.surname = 'Apricot'\n```\n\n\n#### Initializing bindings: property editors ####\n\nThe `SpringWebProcessContextBuilder` class can be overridden if we need to initialize bindings in our own way, for example for registering *property editors*.\n\n\nLet's see an example of this extension:\n\n```java\n\npublic class STSMWebProcessingContextBuilder \n        extends SpringWebProcessingContextBuilder {\n\n    public STSMWebProcessingContextBuilder() {\n        super();\n    }\n    \n    protected void initBinder(\n            final String bindingVariableName, final Object bindingObject,\n            final ITest test, final DataBinder dataBinder, final Locale locale, \n            final Map\u003cString,Object\u003e variables) {\n        \n        final String dateformat = test.getMessages().computeMessage(locale, \"date.format\", null);\n        final SimpleDateFormat sdf = new SimpleDateFormat(dateformat);\n        sdf.setLenient(false);\n        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, false));\n        \n    }\n    \n}\n```\n\n\n### Spring Security ###\n\nThe testing library can also be integrated with Spring Security. This allows the use of the `thymeleaf-extras-springsecurity3` dialect and testing template rendering in different authentication/authorization scenarios.\n\nExample of usage:\n\n```java\nfinal SpringSecurityWebProcessingContextBuilder processingContextBuilder =\n        new SpringSecurityWebProcessingContextBuilder();\nprocessingContextBuilder.setApplicationContextConfigLocation(\n        \"classpath:springsecurity/applicationContext-security.xml\");\n        \nfinal TestExecutor executor = new TestExecutor();\nexecutor.setProcessingContextBuilder(processingContextBuilder);\nexecutor.setDialects(\n        Arrays.asList(new IDialect[] { new SpringStandardDialect(), new SpringSecurityDialect()}));\nexecutor.execute(\"springsecurity\");\n```\n\nBy default, authentication will be specified in a user/password basis, by means of the `j_username` and `j_password`.\n\n```properties\n%CONTEXT\nj_username = 'ted'\nj_password = 'demo'\n```\n\n\n\n\n\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthymeleaf%2Fthymeleaf-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthymeleaf%2Fthymeleaf-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthymeleaf%2Fthymeleaf-testing/lists"}