Posts Tagged - testing

Mock multiple calls with same params

This is an example on how to mock a call when it’s called multiple times, and with the same parameter type every time.

Setup

I have the following class…

public class ConnectorRequest
{
	public string Query { get; set; }
}

… which will be consumed by the following service

public class IConnectorService
{
	Task<string> Execute(ConnectorRequest request);
}

Then I have a class which calls IConnectorService multiple times

public class ConnectorConsumerService
{
	private IConnectorService _service;
	
	// ...
	
	public async Task<string> Process() 
	{
		// ... does whatever
		var response1 = await _service.Execute(request1);
		// ... does whatever with that information
		var response2 = await _service.Execute(request2);
		// ... does whatever with that information
		var response3 = await _service.Execute(request3);
		// ... does whatever with that information
		// ... does whatever else
	}
	
	// ...
	
}

Test

Test which mocks multiple calls

public class ConnectorConsumerServiceTest
{
	// all mocks and stubs
	private Mock<IConnectorService> _dependencyMock;

	// service under test
	private ConnectorConsumerService _service;

	public ConnectorConsumerServiceTest()
	{
		_dependencyMock = new Mock<IConnectorService>();
		_service = new ConnectorConsumerService(_dependencyMock.Object);
	}

	[Fact]
	public async Task ProcessXXX_CaseXXX_ShouldReturnOkay()
	{
		// ARRANGE
		// example starts here! -> 
		var responseToExecution1 = new ConnectorRequest
		{
			Query = "some response";
		}
		var responseToExecution2 = new ConnectorRequest
		{
			Query = "another response";
		}
		var responseToExecution3 = new ConnectorRequest
		{
			Query = "oh no! a response";
		}
		
		_dependencyMock.SetupSequence(mock => mock.Execute(It.IsAny<ConnectorRequest>()))
			.ReturnsAsync(responseToExecution1)
			.ReturnsAsync(responseToExecution2)
			.ReturnsAsync(responseToExecution3);
		// <- example ends here

		// ACT
		var result = await _service.Process();
	
		// ASSERT
		result.status.Should().NotBeNull();
		// ... assert whatever
	}
}

Read More

XUnit test examples

Controller test example

this includes how to mock a request’s header - but it’s a bogus test. this only shows how to use XUnit and its structure.

public class XXXControllerTest
{
	// all mocks and stubs
	private Mock<IXXXService> _serviceMock;
	
	// controller under test 
	private XXXController _controller;
	
	public XXXControllerTest() 
	{
		_serviceMock = new Mock<IXXXService>();
		_controller = new XXXController(_serviceMock.Object);
	}
	
	[Fact]
	public async Task CallXXX_ShouldCall_Service()
	{
	// ARRANGE
	
	// mock header
	var httpContext = new DefaultHttpContext();
	httpContext.Request.Headers["someHeader"] = "my-mocked-value";
	_controller.ControllerContext = new ControllerContext
	{
		HttpContext = httpContext
	};
	
	// mock request
	string mockedValue = "someInputValueTo_serviceMock";
	string mockedResponse = "someResponseValueFrom_serviceMock";
	_serviceMock.Setup(mock => mock.SomeMethodCall(mockedValue)).ReturnsAsync(mockedResponse);
	
	// ACT
	var response = await _controller.CallSomething(mockedValue) as OkObjectResult;
	
	// ASSERT
	response.Should().NotBeNull();
	response.StatusCode.Should().Be(200);
	response.Value.Should().BeEquivalentTo(mockedResponse);
	}
}

Basic service test example

public class XXXServiceTest
{
	// all mocks and stubs
	private Mock<IXXXDependency> _dependency;

	// service under test
	private XXXService _serviceMock;

	public XXXServiceTest()
	{
		_dependency = new Mock<IXXXDependency>();
		_serviceMock = new XXXService(_dependency.Object);
	}

	[Fact]
	public async Task ProcessXXX_CaseXXX_ShouldReturnOkay()
	{
		// ARRANGE
		string paramX = "something";
		string responseX = "some response";
		_serviceMock.Setup(mock => mock.SomeMethodCall(paramX)).ReturnsAsync(responseX);
		
		// ACT
		var result = await _service.ProcessXXX(paramX);
	
		// ASSERT
		result.status.Should().NotBeNull();
		// ... assert whatever
	}
}

Read More

Testing. Code example for c#

The following are code examples to test several scenarios.

(check this project to see more testing code examples)

Test a controller

  • GivenCorrectDate_WhenGetAvailability_ThenAssertCorrectReturnValue asserts a controller returns 200 when everything goes right
  • GivenWrongDate_WhenGetAvailability_ThenAssert400ReturnValue assert a controller returns 400 with specific error message
  • GivenServiceThrowsException_WhenReserveSlot_ThenAssertExceptionCaught assert method throws an exception, but it is correctly caught
public class SlotsControllerTest
{
	// class we're testing
	private SlotsController _controller;

	private Mock<ISlotsService> _slotsServiceMock;
	
	private Mock<IOptions<CoreConfig>> _iOptConfigMock;
	private Mock<CoreConfig> _configMock;
	
	[SetUp]
	public void SetUp()
	{
		_configMock = new Mock<CoreConfig>();
		_iOptConfigMock = new Mock<IOptions<CoreConfig>>();
		_iOptConfigMock.Setup(iOpt => iOpt.Value).Returns(_configMock);
		
		_slotsServiceMock = new Mock<ISlotsService>();
		_controller = new SlotsController(_slotsServiceMock.Object, _iOptConfigMock.Object);
	}

[Test]
public async Task GivenWrongDate_WhenGetAvailability_ThenAssert400ReturnValue()
{
	// given
	string date = "";
	string errorMessage = "oh no! something went wrong!";
	
	var errorMessages = new ErrorMessages
	{
		GeneralErrorMessage = errorMessage
	};
	
	_configMock.Setup(conf => conf.GeneralErrorMessage).Returns(errorMessage);
	
	// when
	var result = await _controller.GetAvailability(date) as BadRequestObjectResult;
	
	// then
	result.Should().NotBeNull();
	result.StatusCode.Should().Be(400);
	result.Value.ToString().Should().Contain(errorMessage);
}

[Test]
public async Task GivenCorrectDate_WhenGetAvailability_ThenAssertCorrectReturnValue()
{
	// given
	string date = "20241012";
	var parsedDate = new DateOnly(2024, 10, 12);
	
	string dateFormat = "yyyyMMdd";
	_configMock.Setup(conf => conf.InputDateFormat).Returns(dateFormat);
	
	var dto = new WeekAvailabilityResponse();
	_slotsServiceMock.Setup(service => service.GetWeekSlotsAsync(parsedDate)).ReturnsAsync(dto);
	
	// when
	var result = await _controller.GetAvailability(date) as OkObjectResult;
	
	// then
	result.Should().NotBeNull();
	result.StatusCode.Should().Be(200);
	result.Value.Should().Be(dto);
}

[Test]
public async Task GivenServiceThrowsException_WhenReserveSlot_ThenAssertExceptionCaught()
{
	// given
	var request = new ReserveSlotRequest();

	string errorMessage = "error when throw exception";
	var errorMessages = new ErrorMessages
	{
		GeneralErrorMessage = errorMessage
	};
	
	_configMock.Setup(conf => conf.GeneralErrorMessage).Returns(errorMessage);
	_slotsServiceMock.Setup(service => service.ReserveSlotsAsync(parsedDate)).ThrowAsync(new HttpRequestException(errorMessage));

	// when
	var result = await _controller.ReserveSlot(request) as BadRequestObjectResult
	
	// then
	result.Should().NotBeNull();
	result.StatusCode.Should().Be(400);
	result.Value.ToString().Should().Contain(errorMessage);
}

Read More

Windows debug errores

Visor de eventos

Aqui se pueden ver logs de errores y warnings. Interesantes son las carpetas de Registros de Windows - Aplicacion y Sistema

Administrador de dispositivos

Si hay fallos de red aqui se puede ver el estado de los Adaptadores de Red:

Read More

Test APIs with Postman - Scripting

We can set pre-request scripts (run before the request) & tests (after execution) at several levels:

  • Collection
  • Folder
  • Request

Snippets

Inside pre-request Script and Tests we have a SNIPPETS column with templates we may use for our code.

Get / Set variables

console.log("Hello world");

// work with local vars
let urlVar = pm.variables.get("protocol");
console.log("value for protocol: " + urlVar);

pm.variables.set("protocol", "http");
console.log(pm.variables.get("protocol"));  

// work with global vars
let globalVar = pm.globals.get("env");
console.log(globalVar);

Read More

Test APIs with Postman - GUI

To test postman I use https://reqres.in. You can use it to learn how to write Postman tests.

Collections

Collections have metadata which you can set up. This includes:

  • Authorization so you don’t need to set it for every single request.
  • Variables, for variables only for this collection (so you don’t use environment vars).
  • Collection tests.

Read More

JMeter performance testing

We’re going to use a test app. Supposedly, this app has passed a first development iteration, and has passed unit and functional testing. With JMeter we measure its performance.
Performance testing should start early and continue through the whole dev process.

JMeter is not a browser. It doesn’t execute JavaScript!

Performance Testing

Performance is related to how fast an app executes an operation. Performance testing is about how an app or resource performs under a given load, to see its impact. It should be done after the app has passed all functional tests and we’re sure it works correctly.

Performance testing is measured in terms of:

  • response time: request time + processing time + network latency.
  • throughput: number of transactions (request/response) / unit of time (ms / seconds).
  • reliability: how well the app detects and handles errors. number of errors / number of requests.
  • scalability: tells how well the system expands its capacity in terms of response time, throughput and reliability when additional resources are added.

    • vertical scalability: adding more memory or additional CPUs.
    • horizontal scalability: adding servers to a cluster.

Performance requirements

They’re are usually set up in contracts, such as:

  • average / maximum response time.
  • pages per second the system should be able to support.
  • users per hour the system should be able to support.

Process to follow

  • Design and build tests: We have to know the app and its usage patterns.
  • Prepare test environment: configure a test env similar to prod.
  • Run the test: validate the script and test data. Monitor server logs!
  • Analyze the results
  • Optimize
  • Retest

Types of Performance Tests

  • Increase the number of users.
  • Increase the number of requests.

Almost always you should execute a smoke test first. This is a test with light load to verify the test works correctly.

A load test is a test that’s performed at a specific load level. Usually you’ll perform them at many load levels to monitor the app’s behavior.

A stress test tests the app with loads past its normal working range, to see up to which point it stays stable and responsive.

At a spike test the app is subjected to brief periods of sudden increments in the load beyond its maximum capacity, to see if the app is robust enough to work during and after the spike.

Endurance tests, where the app is subjected to load within its limits for a long duration (hours or even days) to search for memory leaks.

Read More

JMeter

JMeter is a testing tool to simulate thousands of users. It uses Java Threads for this.

Configure a Test Plan

In JMeter the components of a test are organized in a tree, where each component has a scope that determines to what other components it has access to.

Test Plan

Test Plan is the root element of a test, where all overall settings are specified and all the other elements are contained.

It allows us to:

  • Define variables to the entire test.
  • There we can set to run Thread Groups consecutively, instead of parallel.
  • We may run tearDown Thread Groups. They run at the end of the test, after a graceful shutdown of the main Threads. They won’t be run if the test is forcibly stopped.
  • If we select Functional Test Mode, JMeter will save information from the server responses to result files. Beware, as this files grow quickly and they impact performance. Only for small tests.
  • We may add jar files or directories to classpath, so they will load just for the test script.

Thread Groups

They’re the entry point of a test and controls the number of threads (users) JMeter will use to execute a test. We also have setUp and tearDown Thread Groups.

We may:

  • Set the number of users and the time it will take to create them. This creation can be delayed until they’re needed.

Configuration Elements

They’re used to set up default configurations and variables for later use by other components. They can be placed under any other component.

They are classified into:

  • elements that allows us to set variables: CSV Data Set Config, Counter or Random Variable.
  • elements that allows us to define a Configuration: JDBC Connection Configuration, KeyStore Configuration, Login Config Element.
  • managers that allow us to manage configuration params: HTTP Header Manager, HTTP Cookie Manager, HTTP Cache Manager.
  • default configuration elements: HTTP Request Defaults, FTP Request Defaults, Java Request Defaults.

The most common used are:

  • CSV Data Set Config used to read the content of a CSV file and turn it into variables.
  • HTTP Header Manager allows us to add or override HTTP Request Headers.
  • HTTP Cookie Manager For each user, it stores and sends a cookie like a browser; Allows to manually add a cookie that will be shared by all users.
  • HTTP Cache Manager Adds caching functionality to HTTP Request. Each user has its own cache.
  • User defined variables allows you to define a set of variables. They’re processed once at the start of the test and are shared between old thread groups.

He created an HTTP Request Defaults and added the IP and port number, so he doesn’t need to repeate this at every component.

Read More