liveBook · Manning

Application database

As explained in Unit Testing Principles, Practices, and Patterns

An application database is a database accessed exclusively by a particular application and hidden from direct access by external systems.

An application database is a database used exclusively by one application. Because clients and external systems cannot access it directly, the application and database form one system: their communication pattern can change without creating an external compatibility obligation. section 5.4

Treat an application database as a managed dependency:

  • Use a real database instance in integration tests rather than mocking its interactions. section 8.3
  • Test the resulting database state, not fragile communication details such as table splits or stored-procedure parameter types. section 5.4
  • Keep schema delivery, transactions, test-data cleanup, and test scope under deliberate control. section 10.0

Changing an email

An integration test inserts a user and company into a real database, runs the email-change scenario, verifies the persisted email, and mocks only the message bus because other systems depend on it. section 8.3

Listing 8.2. The integration test
[Fact]
public void Changing_email_from_corporate_to_non_corporate()
{
    // Arrange
    var db = new Database(ConnectionString);                          #1
    User user = CreateUser(                                           #2
        "user@mycorp.com", UserType.Employee, db);                    #2
    CreateCompany("mycorp.com", 1, db);                               #2

    var messageBusMock = new Mock<IMessageBus>();                     #3
    var sut = new UserController(db, messageBusMock.Object);

    // Act
    string result = sut.ChangeEmail(user.UserId, "new@gmail.com");

    // Assert
    Assert.Equal("OK", result);

    object[] userData = db.GetUserById(user.UserId);                 #4
    User userFromDb = UserFactory.Create(userData);                  #4
    Assert.Equal("new@gmail.com", userFromDb.Email);                 #4
    Assert.Equal(UserType.Customer, userFromDb.Type);                #4

    object[] companyData = db.GetCompany();                          #5
    Company companyFromDb = CompanyFactory                           #5
        .Create(companyData);                                        #5
    Assert.Equal(0, companyFromDb.NumberOfEmployees);                #5

    messageBusMock.Verify(                                           #6
        x => x.SendEmailChangedMessage(                              #6
            user.UserId, "new@gmail.com"),                           #6
        Times.Once);                                                 #6
}

The example test shows the boundary in practice: a real database is exercised and inspected, while the unmanaged message bus is replaced with a mock. section 8.3

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Defines access boundaries, explains compatibility consequences, and details real-database integration testing without covering implementation internals.
Examples
Uses a user email-change workflow, persisted user and company records, a real database, and a mocked message bus.
What it assumes
Assumes familiarity with integration testing and out-of-process dependencies while introducing managed-versus-unmanaged classification.
What you can do after
Evaluate integration-test boundaries and choose real database testing while mocking only dependencies controlled by external systems.
How it connects
Connects managed dependencies with integration testing, database schema delivery, transactions, mocks, message buses, and end-to-end testing.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.