Skip to content

Structure

Gennady Verdel edited this page Jan 25, 2016 · 2 revisions

The solution itself contains of two main parts: App and Tests. This is quite common to have tests in the application but in this case these are first and foremost specifications which guide the App's functionality. It is important to realize that not every test can and should be expressed as a specification yet the most prominent scenarios should be clear to the business stakeholders.


The App part usually contains of Client and Server but in this particular sample the Server part is omitted to put focus to the demonstrated feature which is specifications and BDD.


The Client part consists of three layers: Model which is the app's domain as seen by the Client, Presentation which is the model's presentation according to the visual requirements and Data which is the interface to the external source of data - usually supplied by Server from some kind of Storage.


The Model layer consists of two parts: Contracts which provide definitions of the Client Domain Models - This project should contain only interfaces or enumeration types (preferably value objects) and Model itself which contains a private implementation of the contracts. The consumers should not be exposed to the implementation details and work only with the contracts. This greatly improves the decoupling of the App.


The Presentation layer in this case consists only of the Shell which contains both Views and View Models. There is no code-behind and all presentation-related logic is put in the View Models and Views communicate either via bindings or mediators - behaviors, trigger actions, dependency properties etc. This allows integration testing of the Presentation features on the View Models if required to.


The Data layer consists of three parts:


Contracts which defines the lingua franca for data and access to it from the Client point of view. This part contains of two components: DTO which contains the definitions for the data objects used for communication with Server and Providers which contains the interfaces for requesting these objects or issuing related commands to the Server. It is important to understand that the definitions for DTO are directed by the Server and Client should have very little influence, if any, over the objects schema. The DTO themselves are simple POCOs deprived of any business logic, neither from Client nor from Server. The only concern that may be added to the schema is the decoration with serialization protocol attributes: [Serializable] for built-in .NET, or [Proto] for Protobuf.


Fake which contains fake implementation of the Providers including the initialization. This approach is useful for the cases where the Client is to be filled with some test data independently from the Server for QA or fast feedback. This part consists of 3 components: Containers which represent containers of the initial fake data, ProviderBuilders which contain builders for the providers with fluent API and various setup capabilities, and Providers which contain implementation of Providers contracts using the ProviderBuilders. The ProviderBuildrers prove to be extremely useful not only for the Fake Providers but also in Tests.


Real which contains real implementation of the Providers contracts. It is omitted from the sample but usually this implementation should contain a reference to the service, identified by its address and API. WebAPI is one of the options.


The Tests in this particular sample include only End-to-End tests from the Client point of view. While this approach may not fit some scenarios it still has lots of benefits as testing the functionality which is broken by the Server or even is not implemented yet. The Tests utilize the SpecFlow to create executable specifications and TestStack.White as the automation framework. There are following components in this part of the solution:


Specs - this componenent contains the specifications for the App written in Gherkin syntax. By convention, all Given steps contain data-related statements (both for initial setup and the behavior), all When steps contain user action-related statements (open the App and execute the Scenario), all Then steps contain assertion statements. Note that the implementation of the Steps is not in the same project to increase granularity, as in real-world applications specifications are often separated into different projects, while the steps might be shared.


Steps - this component contains the steps implementations and their adapters to SpecFlow Hooks. The Steps.Adapters project merely delegates the work to the actual Steps implementation, occasionally translating data. This separation is needed for the cases where there will be non-Specflow based integration tests which still need to execute the same steps. Note that the Steps project is agnostic to the testing framework. It contains pure application flow.


TestData - this component contains the test-related data which is used primarily in assertion statements. When we talk about End-To-End tests the implementation details are to be hidden from the assertion, as much as they are hidden when one performs a manual test.


ScreenObjects - this is the main component of the Tests as it contains all the logic of data extraction from the application as well as user-action invocation. It consists of 2 parts: ScreenObjects.Contracts which define clear interface for accessing the screens inside the Steps and ScreenObjects.EndToEnd which contain implementation of this interface for the End-To-End tests. Again this separation is needed to support possible integration tests case which will work in the same manner as the existing End-To-End ones.


Infra - Last but not least. This component bridges between the described approach of Steps Adapters and Screen Objects and SpecFlow to ensure simple work for the developers. It does so by adding an appropriate SpecFlow Hook . Additionally it allows the App to pick up the right Providers.

Clone this wiki locally