Unit test - Mocking Service and Repository/Unit Of Work Layer - unit-testing

In my current implementation I use the Domain Service layer to inject the repositories through Unit Of work.
In some cases, I inject other Services into my Service.
However, I have found difficulties to Mock these objects when making unit tests, because whenever a Service class has injection of dependencies with other Services I need to mock the dependencies of that other service.
How to make it work in a simple way?
Was I using the layers wrongly?
Eg:
public class ValueService : IValueService
{
private readonly ITestService _testService;
private readonly IOptionService _optionService;
public ValueService (IUnitOfWork unitOfWork,
ITestService testService,
IOptionService optionService) : base(unitOfWork)
{
_testService = testService;
_optionService = optionService;
}
When I'm going to mock the ValueService class, I need to mock the TestService and OptionService together with their dependencies.
Can you help me to think about this architecture that I'm implementing?

You can try the code below. I hope it helps.
You can inject all your services and repositories.
public class ValueServiceTest
{
private readonly IValueService _valueService;
public ValueServiceTest()
{
_valueService = GetService();
}
***********************
Your test methods.
***********************
private ValueService GetService()
{
var services = new ServiceCollection();
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IValueService, ValueService>();
services.AddScoped<ITestService, TestService>();
services.AddScoped<IOptionService , OptionService >();
**********************************
You can inject repositories here.
**********************************
var serviceProvider = services.BuildServiceProvider();
return serviceProvider.GetService<IValueService>();
}
}

Related

Azure Function: how can I improve the Unit test?

Azure function based on .Net core 3.1. Triggered when a file is uploaded into the Blob container. Any files uploaded to Azure Blob Storage are compressed, and the database is updated.
Below is my business logic
public partial class FileProcessingServiceFacade : IFileProcessingServiceFacade
{
public async Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context)
{
AppDbContext.FileRecords.Add(new FileRecords { ... });
AppDbContext.SaveChanges();
return await Task.FromResult($"success");
}
}
public partial class FileProcessingServiceFacade : ServiceBase<FileProcessingServiceFacade>
{
public FileProcessingServiceFacade(AppDbContext appDbContext, IOptions<AppConfigurator> configurator)
: base(appDbContext, configurator) { }
}
I am using xUnit and MOQ for unit testing and below is my unit test
[Fact]
public void ProcessAsync()
{
var filename = "fileName.csv";
var stream = new MemoryStream(File.ReadAllBytes(filename));
var log = Mock.Of<ILogger>();
var executionContext = Mock.Of<ExecutionContext>();
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "Testing")
.Options;
var appDbContext = new AppDbContext(options);
var appSettings = new AppConfigurator(){ ... };
IOptions<AppConfigurator> configurator = Options.Create(appSettings);
var target = new FileProcessingServiceFacade(appDbContext, configurator);
var actual = target.ProcessAsync(stream, filename, log, executionContext);
Assert.True(appDbContext.FileRecords.FirstAsync<FileRecords>().Result.FileName.Equals(filename));
Assert.True(actual.Result.Equals("success"));
stream.Dispose();
}
I am trying to improve the code quality of the unit testing and I would appreciate any suggestions.
The Application test involves one or more external systems, below are the sample points which you need to be aware while have unit testing
Tests may fail if you ae connecting your application with Remote System or External System.
You need to call the external system directly.
Accessing external system may have an effect on the performance of your tests.
Also, As suggested by BrettMiller you can go through the sample of Azure functions Test fixture.

Create a JUnit for Camel route and processor

I am new to JUnit. I am trying to write test case for camel route and processor. I don't know how to start. Here is my route
from("activemq:queue1").process("queueprocessor").toD("activemq:queue2").
I need help to mock my endpoints and processor.
Here mocked all endpoints using "isMockEndpoints" & added expected body content to endpoint(activemq:queue2) and by sending same content as input to mocked endpoint(activemq: queue1) verified assert is satisfied or not.
public class MockEndpointsJUnit4Test extends CamelTestSupport {
#Override
public String isMockEndpoints() {
// override this method and return the pattern for which endpoints to mock.
// use * to indicate all
return "*";
}
#Test
public void testMockAllEndpoints() throws Exception {
// notice we have automatic mocked all endpoints and the name of the endpoints is "mock:uri"
getMockEndpoint("mock:activemq:queue2").expectedMessageCount(1);
getMockEndpoint("mock:activemq:queue2").expectedBodiesReceived("Hello World");
template.sendBody("mock:activemq:queue1", "Hello World");
getMockEndpoint("mock:activemq:queue2").assertIsSatisfied();
/* additional test to ensure correct endpoints in registry */
/* all the endpoints was mocked */
assertNotNull(context.hasEndpoint("mock:activemq:queue1"));
assertNotNull(context.hasEndpoint("mock:activemq:queue2"));
}
}

PowerMock mock injected Authentication

i am using PowerMockRunner in a spring-boot application for testing. Everything is working but when my controllers actions definition contain someControllerMethod(..., Authentication auth, ...). Then auth is null and therefore some code is not working.
What i tried is to mock Authentication and SecurityContext. Came up with something like this
private void mockSecurity() {
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
List<SimpleGrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("USER"));
User mockedUser = new User("testuser", "passwordtest", authorities);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockedUser);
when(SecurityContextHolder.getContext().getAuthentication().getName()).thenReturn(mockedUser.getUsername());
}
Now those mocks work, if my code uses SecurityContextHolder.getContext().getAuthentication() method of accessing the authentication, but not for the one automatically injected (probably because it is not yet mocked when the controller mock is created).
Any ideas how to mock the injected Authentication so the code does not need to be changed? spring-security-testand #MockWithUser have the same result.
Relevant parts of the test look like this,
#RunWith(PowerMockRunner.class)
public class UserControllerTest {
#InjectMocks
UserController userController;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = standaloneSetup(userController).build();
}
#Test
public void getUserDetails() {
mockSecurity();
mockMvc.perform(...).andExpect(...);
}
}
Edit as requested by pvpkiran the controller code
#RequestMapping(...)
public void getDetails(#PathVariable String id, Authentication auth) {
UserDetails loadedDetails = userService.getUserDetails(id);
if (!loadedDetails.getUserId().equals(auth.getName())) {
throw new Exception(...);
}
...
}

.Net Core DynamodDB unit testing with XUnit

Using C#, .net core 2.0, dynamo db
I have my web api, that interact with my dynamo db database having both Get and Post methods.
Example of Mehthod:
[HttpGet("api/data")]
public async Task<List<string>> GetAllData(string userId, string type, string status)
{
var creds = new BasicAWSCredentials(awsId, awsPassword);
var dynamoClient = new AmazonDynamoDBClient(creds, dynamoRegion);
var context = new DynamoDBContext(dynamoClient);
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("UserId", ScanOperator.Equal, userId));
conditions.Add(new ScanCondition("Type", ScanOperator.Equal, type));
conditions.Add(new ScanCondition("Status", ScanOperator.Equal, status));
var results = await context.ScanAsync<Common.Job>(conditions, new DynamoDBOperationConfig() { OverrideTableName = MyDynamoTable }).GetRemainingAsync();
return results.Select(x => x.UpdatedBy.ToLower()).ToList();
}
Now I want to write unit/integration tests for my api methods. Earlier I had used NUnit but with .net core 2.0 I believe we have to use XUnit: https://xunit.github.io/docs/getting-started-dotnet-core
Setting up Xunit in my project should not be an issue.
I wanted to know how can I write test which involve dynamo db here. This is the first time I am using any AWS service here.
So bascially I need to know how can I mock up a aws connection, dynamo db and then use various params as shown in my method above.
I could not find much details or any earlier helpful post on this topic so posting one here.
If aws dynamo db part is not testable. Can anyone share the example of xunit test where we can test the params may be and see the expected result?
AWS SDK work with interfaces. You can mock interface IAmazonDynamoDB easily. But try to do it with dependecy injection-ish. Much better.
Something like
private readonly IAmazonDynamoDB dynamodbClient;
private readonly IDynamoDBContext context;
public MyDynamodbHandler(IAmazonDynamoDB client)
{
this.dynamodbClient = client;
this.context = new DynamoDBContext(client);
}
[HttpGet("api/data")]
public async Task<List<string>> GetAllData(string userId, string type, string status)
{
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("UserId", ScanOperator.Equal, userId));
conditions.Add(new ScanCondition("Type", ScanOperator.Equal, type));
conditions.Add(new ScanCondition("Status", ScanOperator.Equal, status));
var results = await this.context.ScanAsync<Common.Job>(conditions, new DynamoDBOperationConfig() { OverrideTableName = MyDynamoTable }).GetRemainingAsync();
return results.Select(x => x.UpdatedBy.ToLower()).ToList();
}
So every function uses the injected IAmazonDynamoDB. All you have to do is to mock this instance at the beginning
Such as
dynamodbClientMock = new Mock();
Then use this mock to initiate MyDynamodbHandler class
var dynamodbHandler = new MyDynamodbHandler(dynamodbClientMock);
dynamodbHandler.GetAllData();

Allow all actions for authentication in integration test cakephp

I'm currently trying to write an integration test for some controller whereby it is necessary to send an authentication header. In my controller I have some actions made public accessible through the following code:
namespace App\Controller\Api;
use Cake\Event\Event;
use Cake\Network\Exception\UnauthorizedException;
use Cake\Utility\Security;
use Firebase\JWT\JWT;
class UsersController extends AppController
{
public function initialize()
{
parent::initialize();
$this->Auth->allow(['add', 'token']); // public methods
}
.....
}
Now I have an integration test case in which I want to allow that all actions are possible to access without authentication. Is there any simple way to make this possible?
Integration case code:
namespace App\Test\TestCase\Controller;
use App\Controller\Api\UsersController;
use Cake\TestSuite\IntegrationTestCase;
class ApiPicturesControllerTest extends IntegrationTestCase{
public $fixtures = [
'app.albums',
'app.pictures',
'app.users',
'app.comments',
'app.users_albums'
];
public function setUp(){
parent::setUp();
// Allow all actions
// $this->Auth->allow();
}
public function testViewShouldPass(){
$this->configRequest([
'headers' => [
'Accept' => 'application/json'
]
]);
$data = $this->get('/api/pictures/1.json');
$this->assertResponseOk();
}
}
Generally it's possible to manipulate the controller in an overriden \Cake\TestSuite\IntegrationTestCase::controllerSpy() method, like
public function controllerSpy($event)
{
parent::controllerSpy($event);
if (isset($this->_controller)) {
$this->_controller->Auth->allow();
}
}
but as already mentioned in the comments, it would be better to properly authenticate your requests instead!
While integration tests do not necessarily have to be black-box tests, peering into the internals of the test subject isn't an overly good idea. Mocking certain parts in an integration test might be reasonable when you are looking for something in between "test everything" and "test units", ie larger groups of modules, but that should mostly only be necessary when heavy complexity is involved in a request.
See also
API > \Cake\TestSuite\IntegrationTestCase::controllerSpy()
API > \Cake\TestSuite\IntegrationTestCase::$_controller