Skip to content

4. Testing

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Unit tests

Unit testing is a type of software testing where individual units or components of a software are tested. The purpose is to validate that each unit of the software code performs as expected. Unit Testing is done during the development (coding phase) of an application by the developers. Unit Tests isolate a section of code and verify its correctness. A unit may be an individual function, method, procedure, module, or object.

Example

Unit testing with Signals is implemented using the following steps:

  1. We define a class that extends ApplicationBootstrapConfiguration where we will define all Signals aspects that the tests will be using.
public class TestBootstrapConfiguraiton : ApplicationBootstrapConfiguration
{
}
  1. We implement a base fixture class that all test classes will extend.
public class BaseProcessesTest
{
    /// <summary>
    /// Process mediator
    /// <summary>
    protected Mediator Mediator => SystemBootstrapper.GetInstance<Mediator>();

    /// <summary>
    /// Executed when test class is initialized
    /// </summary>
    public BaseProcessesTest()
    {
        FileConfigurationProvider ProviderForFile(string name) => new FileConfigurationProvider
        {
            File = name,
            Path = Path.Combine(AppContext.BaseDirectory, $"configs"),
            ReloadOnAccess = false
        };
        DomainConfiguration.UseProvider(ProviderForFile("domain.config.json"));

        var databaseConfig = DomainConfiguration
            .Instance
            .DatabaseConfiguration
            .ActiveConfiguration;

        TestBootstrapConfiguraiton config = new TestBootstrapConfiguraiton
        {
            RegistrationService = new RegistrationService(),
            LoggerConfiguration = new DatabaseLoggingConfiguration
            {
                Database = databaseConfig.Database,
                Host = databaseConfig.IpAddress,
                Username = databaseConfig.Uid,
                Password = databaseConfig.Pwd,
                DataProvider = DataProvider.SqlClient,
                TableName = "LogEntity"
            },
        };

        var assemblies = Directory
            .GetFiles(Environment.CurrentDirectory, "*.dll")
            .Select(file => Assembly.LoadFrom(file)).ToArray();

        config.Bootstrap(assemblies);

        SystemBootstrapper.Bootstrap(this);
    }
}
  1. We implement the unit tests in a class that extends the base class BaseProcessesTest.
public class UnitTests : BaseProcessesTest
{
    private Mock<IMyRepository> MyRepository { get; set; }

    /// <summary>
    /// CTOR
    /// </summary>
    public UnitTests()
    {
        MyRepository = new Mock<IMyRepository>();
        MyRepository.Setup(x => x.GetById(1)).Returns(new MyObject());
    }

    [Fact]
    public void HavingRequest_ExecuteProcess_NotFaulted()
    {
        // Arrange
        var request = new MyProcessRequest();

        // Act
        var process = Mediator.For<MyProcess>();
        process.MyRepository = MyRepository.Object;
        var result = process.With(request);
        var response = result.Result;


        // Assert
        Assert.False(response.IsFaulted);
        Assert.Equal(1, response.Result); // business logic assert
    }
}

Integration tests

Integration testing is the phase in software testing in which individual software modules are combined and tested as a group. Integration testing is conducted to evaluate the compliance of a system or component with specified functional requirements. It occurs after unit testing. Integration testing takes as its input modules that have been unit tested, groups them in larger aggregates, applies tests defined in an integration test plan to those aggregates, and delivers as its output the integrated system ready for system testing.

Example

Integration testing with Signals is implemented using the following steps:

  1. We define a class that extends ApplicationBootstrapConfiguration where we will define all Signals aspects that the tests will be using.
public class TestBootstrapConfiguraiton : ApplicationBootstrapConfiguration
{
}
  1. We implement a base fixture class that all test classes will extend.
public class BaseProcessesTest
{
    /// <summary>
    /// Web mediator
    /// <summary>
    private WebMediator WebMediator => SystemBootstrapper.GetInstance<WebMediator>();

    /// <summary>
    /// Executed when test class is initialized
    /// </summary>
    public BaseProcessesTest()
    {
        FileConfigurationProvider ProviderForFile(string name) => new FileConfigurationProvider
        {
            File = name,
            Path = Path.Combine(AppContext.BaseDirectory, $"configs"),
            ReloadOnAccess = false
        };
        DomainConfiguration.UseProvider(ProviderForFile("domain.config.json"));

        var databaseConfig = DomainConfiguration
            .Instance
            .DatabaseConfiguration
            .DatabaseConnections
            .Single(x=>x.Name = "MyIntegrationTestDatabase");

        TestBootstrapConfiguraiton config = new TestBootstrapConfiguraiton
        {
            RegistrationService = new RegistrationService(),
            LoggerConfiguration = new DatabaseLoggingConfiguration
            {
                Database = databaseConfig.Database,
                Host = databaseConfig.IpAddress,
                Username = databaseConfig.Uid,
                Password = databaseConfig.Pwd,
                DataProvider = DataProvider.SqlClient,
                TableName = "LogEntity"
            },
        };

        var assemblies = Directory
            .GetFiles(Environment.CurrentDirectory, "*.dll")
            .Select(file => Assembly.LoadFrom(file)).ToArray();

        config.Bootstrap(assemblies);

        SystemBootstrapper.Bootstrap(this);
    }

    /// <summary>
    /// Mock and send web request to api process
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="method"></param>
    /// <param name="queryString"></param>
    /// <param name="body"></param>
    /// <returns></returns>
    protected T MockRequest<T>(string path, ApiProcessMethod method, string queryString = null, object body = null)
        where T : VoidResult
    {
        // build http context
        var context = new DefaultHttpContext();
        context.Response.Body = new MemoryStream();
        context.Request.Path = path;
        context.Request.Method = method.ToString();

        if (!queryString.IsNullOrEmpty())
            context.Request.QueryString = QueryString.FromUriComponent(queryString);

        if (!body.IsNull())
            context.Request.Body = new MemoryStream(Encoding.Default.GetBytes(body.SerializeJson()));

        // mock context accessor
        var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
        mockHttpContextAccessor.Setup(_ => _.HttpContext).Returns(context);
        var request = new HttpContextWrapper(mockHttpContextAccessor.Object);

        // dispatch mock web request
        WebMediator.Dispatch(request);

        // read response
        context.Response.Body.Position = 0;
        return new StreamReader(context.Response.Body).ReadToEnd().Deserialize<T>();
    }
}
  1. We implement the integration tests in a class that extends the base class BaseProcessesTest.
public class IntegrationTests : BaseProcessesTest
{
    [Fact]
    public void HavingRequest_ExecuteProcess_NotFaulted()
    {
        // Arrange
        var path = "/api/MyApiProcess";
        var method = ApiProcessMethod.POST;
        var queryString = "?MyProperty=MyValue";
        var body = new MyRequestBody
        {
            MyProperty = "MyValue"
        };

        // Act
        var response = MockRequest<MethodResult<int>>(path, method, queryString, body);

        // Asset
        Assert.False(response.IsFaulted);
        Assert.Equal(1, response.Result); // business logic assert
    }
}
Clone this wiki locally