Service layer unit testing spring boot - spring

I want to test my service layer but stuck with an error.
I have Company entity and createCompany method in my service
public Company createCompany(String name) {
Optional<Company> existingCompany = companyRepository.findCompanyByName(name);
if (existingCompany.isPresent()) {
log.error("Company with name {} already exists", name);
throw new ValidationException("Company with name " + name + " already exists");
} else {
return companyRepository.save(new Company(UUID.randomUUID(), name, new HashSet<>()));
}
}
Here's my test:
#Test
public void whenCreateCompany_thenReturnCompany() {
// prepare
Company company = new Company();
when(companyRepository.save(any())).thenReturn(company);
// testing
Company createdCompany = companyService.createCompany("name");
// validate
verify(companyRepository).save(company);
}
But when I run test, I get an error
Argument(s) are different! Wanted:
companyRepository.save(
Company(id=null, name=null)
);
Actual invocations have different arguments:
companyRepository.findCompanyByName(
"name"
);
companyRepository.save(
Company(id=f7cf1525-0dc4-4c27-a9af-693e2a295437, name=name)
);
How to test the service level correctly?

You can change your when call to using org.mockito.ArgumentMatchers.any() as parameter instead of your empty company object.
when(companyRepository.save(any())).thenReturn(company);
In your code mockito expects your, in the test created, company object passed in the save method. But your manually company contains id and name as null values. But in your test you try to save a company with the name=name and a random generated uuid.
Update from comments:
You have to use any in the verify method, too.
verify(companyRepository).save(any());

Related

How to pass 2 or more variables using #PathParam in spring mvc? and suppose if I want to test it out using postman how to do that?

I'm trying to fetch value from db using JPA repository method
product findByIdNumberOrCifNumber(String idNumber , String cifNumber);
service class logic:-
public ResponseModel FindByCivIDOrCifNumber(String idNumber,String cifNumber) {
ResponseModel responseModel = new ResponseModel();
Optional<product> civId = Optional.ofNullable(productRepos.findByIdNumber(idNumber));
if (civId.isPresent()) {
responseModel.setResponse(productRepos.findByIdNumberOrCifNumber(idNumber,cifNumber));
} else {
errorModel errorModel1 = new errorModel();
enter image description here errorModel1.setErrorCode(productConstant.INVALID_REQUEST);
errorModel1.setErrorDescription("Requested Civil Id or CifNUmber is not present");
responseModel.setErrorModel(errorModel1);
}
return responseModel;
}
controller class:-
#GetMapping("/getByCifNoOrGetByIdNo")
public ResponseModel getProductByCifNoOrGetByIdNo(#RequestParam String idNumber,#RequestParam String cifNumber ) {
return productService.FindByCivIDOrCifNumber(idNumber,cifNumber);
}
post man:-
kindly help me out how to make it work:)
If you are looking for an answer to pass two or more path variables and test it with postman, you can try this.
#GetMapping("/api/mapping-name/{variable1}/{variable2}")
Here you will be getting two path variables which you can access by the syntax
#PathVariable("variable1") datatype variableName
Now in postman request url you can simply give the respective url, lets say:
https://localhost8080/api/mapping-name/:variable1/:variable2
which automaticaly will give you a key value section in the path variables section in the params with prepopulated key names as per the name you have given. In this case variable1 & variable2.
Give the respective value and it should work.

eror when retrieve createdby field in crm using plugin

I try to retrieve the createdby field when I create a cases with a plugin, but the first retrieval fails, and the second and subsequent retrieval are successful. And then when I logged out and login with other user the first retrieval fails (retrieve result is the user before i change the user), and the second and subsequent retrieval are successful.
here is the code i write :
public void Execute(IServiceProvider serviceProv)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProv.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefac = (IOrganizationServiceFactory)serviceProv.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefac.CreateOrganizationService(context.UserId);
ITracingService trace = (ITracingService)serviceProv.GetService(typeof(ITracingService));
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "incident")
return;
QueryExpression qe = new QueryExpression("incident");
string[] cols1 = { "createdby" };
qe.ColumnSet = new ColumnSet(true);
EntityCollection ec = service.RetrieveMultiple(qe);
foreach (Entity act in ec.Entities)
{
created = act. GetAttributeValue<EntityReference>("createdby").Name;
}
if (created == "CRM SNA")
{
created = string.Empty;
}
else
{
//here is the autonumber code
created = string.Empty;
}
}
}
What I want to make is an autonumber plugin, when cases are created by "CRM SNA" then the autonumber must not run, when cases are created by other users the autonumber will run.
How to make the first retrieve successful? and did not retrieve the user before?
thanks.
I assume your plugin runs in the Pre-Create step. CreatedBy and CreatedOn are not available in this step (probably because the record is not saved yet).
If you are just trying to get the user that executed the action that fired the plugin, use context.InitiatingUserId. You could also look into the documentation for the WhoAmI request.
Hope that helps!

Mstest Controller and Service Layer With Dependency Injection (Autofac) and Automapper

I'm trying to bring test layer to my project but I'm not getting there :( hope someone can help me.
Controller (based on Automapper mapping and Dependency Injection Container):
public virtual ActionResult SearchCategories(string keywords)
{
var result = _categoryService.SearchCategories(keywords);
var resultViewModel = Mapper.
Map<IList<SearchCategoriesDto>,
IList<SearchCategoriesViewModel>>(result);
return View(resultViewModel);
}
Service Layer:
public IList<SearchCategoriesDto> SearchCategories(String keywords)
{
// Find the keywords in the Keywords table
var keywordQuery = _keywordRepository.Query;
foreach (string keyword in splitKeywords)
{
keywordQuery = keywordQuery.Where(p => p.Name == keyword);
}
// Get the Categories from the Search
var keywordAdCategoryQuery = _keywordAdCategoryRepository.Query;
var categoryQuery = _categoryRepository.Query;
var query = from k in keywordQuery
join kac in keywordAdCategoryQuery on k.Id equals kac.Keyword_Id
join c in categoryQuery on kac.Category_Id equals c.Id
select new SearchCategoriesDto
{
Id = c.Id,
Name = c.Name,
SearchCount = keywordAdCategoryQuery
.Where(s => s.Category_Id == c.Id)
.GroupBy(p => p.Ad_Id).Count(),
ListController = c.ListController,
ListAction = c.ListAction
};
var searchResults = query.Distinct().ToList();
return searchResults;
}
Test maded but not working:
[TestMethod]
public void Home_SearchCategories_Test()
{
// Setup
var catetoryService = new CategoryService(
_categoryRepository,
_keywordRepository,
_keywordAdCategoryRepository);
// Act
var result = catetoryService.SearchCategories("audi");
// Add verifications here
Assert.IsTrue(result.Count > 0);
}
Thanks.
I am assuming you want to create an integration test for your category service, using real repositories and database. (as oposed to an unit test where you would use stub\mocks for those repositories and test the service class in isolation)
So you would have a seaparated test assembly where you will add your integration tests, for example having a class for the integration tests at the service level.
On that class you will then create instances of all the repositories and the CategoryService before running each test, on a method with the attribute [TestInitialize]. (A method with this attribute will be run by msTest before each test)
As you are also truly working with the database you would like to be sure that any resources used are disposed. For example, disposing an entity framework context. In that case you would add a method with an attribute [TestCleanup] where you will perform any cleanup logic needed. (A method with this attribute will be run by msTest after each test)
With those methods you will make sure you have a fresh service and repositories instances on each test. Then you will implement each individual integration test following the AAA pattern (Arrange, Act, Assert)
So an example of your integration test class with that single test may look like:
public class CategoryServiceIntegrationTest
{
//dependencies of your class under test
private ICategoryRepository _categoryRepository;
private IKeywordRepository _keywordRepository;
private IKeywordAdCategoryRepository _keywordAdCategoryRepository;
//your class under test
private CategoryService _categoryService;
[TestInitialize]
public void InitializeBeforeRunningATest()
{
//manually create instances of the classes implementing the repositories
//I donĀ“t know about how they are implemented but I guess
//you would need to provide the name of a connection string in the config file (in that case this should be in a config file of the test project)
//,the connection string itself
//or maybe you need to initialize an entity framework context
_categoryRepository = new CategoryRepository( /*whatever you need to provide*/);
_keywordRepository = new KeywordRepository( /*whatever you need to provide*/);
_keywordAdCategoryRepository = new KeywordAdCategoryRepository( /*whatever you need to provide*/);
//Create the class under test with all repositories dependencies
//as it is an integration test, they are your real objects and not mocks\stubs
_categoryService = new CategoryService(_categoryRepository,
_keywordRepository,
_keywordAdCategoryRepository);
}
[TestCleanup]
public void CleanDatabaseResources()
{
//just in case you need to do something like disposing an EF context object
}
[TestMethod]
public void Home_SearchCategories_Test()
{
// Arrange
var keywords = "audi";
// Act (the _categoryService instance was created in the initialize method)
var result = _categoryService.SearchCategories(keywords);
// Assert
Assert.IsTrue(result.Count > 0);
}
}
Solution to build an Integration test for a Service (in this case, Category Service), using Autofac, Automapper (not necessary in this Service but if it would be necessary, you would need to put in the TestInitialize method as you can see in the coment line in the following solution) and Entity Framework with Daniel J.G. help (thanks Daniel):
First of all I created a separated Test Project using MSTest (only because there is a lot of documentation about it).
Second you need to put the connection string for the Entity Framework where the test data is:
<connectionStrings>
<add name="DB" connectionString="Data Source=.\sqlexpress;Database=DBNAME;UID=DBUSER;pwd=DBPASSWORD;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
In the < configuration > section after the < / configSections >
Third you create the class for the test:
namespace Heelp.Tests
{
[TestClass]
public class CategoryServiceIntegrationTest
{
// Respositories dependencies
private IRepository<Category> _categoryRepository;
private IRepository<Keyword> _keywordRepository;
private IRepository<KeywordAdCategory> _keywordAdCategoryRepository;
// Service under test: Category Service
private CategoryService _categoryService;
// Context under test: HeelpDB Connection String in app.config
private HeelpDbContext db;
[TestInitialize]
public void InitializeBeforeRunningATest()
{
// IoC dependencies registrations
AutofacConfig.RegisterDependencies();
// HERE YOU CAN CALL THE AUTOMAPPER CONFIGURE METHOD
// IN MY PROJECT I USE AutoMapperConfiguration.Configure();
// IT'S LOCATED IN THE App_Start FOLDER IN THE AutoMapperConfig.cs CLASS
// CALLED FROM GLOBAL.ASAX Application_Start() METHOD
// Database context initialization
db = new HeelpDbContext();
// Repositories initialization
_categoryRepository = new Repository<Category>(db);
_keywordRepository = new Repository<Keyword>(db);
_keywordAdCategoryRepository = new Repository<KeywordAdCategory>(db);
// Service initialization
_categoryService = new CategoryService(_categoryRepository,
_keywordRepository,
_keywordAdCategoryRepository);
}
[TestCleanup]
public void CleanDatabaseResources()
{
// Release the Entity Framework Context for other tests that will create a fresh new context.
// With this method, we will make sure that we have a fresh service and repositories instances on each test.
db.Dispose();
}
[TestMethod]
public void Home_SearchCategories_Test()
{
// Arrange
var keywords = "audi";
// Act (the _categoryService instance was created in the initialize method)
var result = _categoryService.SearchCategories(keywords);
// Assert
Assert.IsTrue(result.Count > 0);
}
}
}
Now you just have to run the test to see if it passes.
To garantee integration tests, I would recomend a second database identical from the original/production database in terms of tables, but with only your test data.
This will ensure that the tests results will remain the same based on your test data.
The only drawback is that you will need to keep sincronized the tables, but you can use SQL Admin Studio Freeware Tool from Simego to achieve that.
Regards.

Could this be a bug?

I have the following test case
[TestMethod()]
[DeploymentItem("Courses.sdf")]
public void RemoveCourseConfirmedTest()
{
CoursesController_Accessor target = new CoursesController_Accessor();
int id = 50;
ActionResult actual;
CoursesDBContext db = target.db;
Course courseToDelete = db.Courses.Find(id);
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
actual = target.RemoveCourseConfirmed(courseToDelete);
foreach (var meet in meets)
{
Assert.IsNull(db.Meets.find(meet));
}
Assert.IsNull(db.Courses.Find(courseToDelete.courseID));
}
Which tests the following method from my controller.
[HttpPost, ActionName("RemoveCourse")]
public ActionResult RemoveCourseConfirmed(Course course)
{
try
{
db.Entry(course).State = EntityState.Deleted;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
return RedirectToAction("RemoveMeet", new System.Web.Routing.RouteValueDictionary { { "concurrencyError", true } });
}
catch (DataException)
{
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again.");
return View(course);
}
}
I know i should be using a Mock db .... but for this project I have decided to go with this approach.
So this what happens. When I run the actual web site this function works perfectly fine and removes the course and all the meets that belong to it.
But when I run the test i get the following exception
System.InvalidOperationException: The operation failed: The relationship could not be
changed because one or more of the foreign-key properties is non-nullable. When a change is
made to a relationship, the related foreign-key property is set to a null value. If the
foreign-key does not support null values, a new relationship must be defined, the foreign-
key property must be assigned another non-null value, or the unrelated object must be
deleted.
Here is the even more interesting part if I comment out the following line from the test
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
and replace the loop with the following:
foreach (var meet in db.Meets.ToList())
{
Assert.IsFalse(meet.courseID == courseToDelete.courseID);
}
I dont get any exceptions and the test case passess.
Am I missing something about Entity Framework or is this a bug?
Well this has been open for a while now. I still haven't been able to find a definite answer but working more with MVC and EF i think what is happening is that once i execute the line
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
the meets get loaded into the object manager and hence when the parent object is deleted the no longer have a reference to the parent course.

PrepareResponse().AsActionResult() throws unsupported exception DotNetOpenAuth CTP

Currently I'm developing an OAuth2 authorization server using DotNetOpenAuth CTP version. My authorization server is in asp.net MVC3, and it's based on the sample provided by the library. Everything works fine until the app reaches the point where the user authorizes the consumer client.
There's an action inside my OAuth controller which takes care of the authorization process, and is very similar to the equivalent action in the sample:
[Authorize, HttpPost, ValidateAntiForgeryToken]
public ActionResult AuthorizeResponse(bool isApproved)
{
var pendingRequest = this.authorizationServer.ReadAuthorizationRequest();
if (pendingRequest == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
IDirectedProtocolMessage response;
if (isApproved)
{
var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier);
client.ClientAuthorizations.Add(
new ClientAuthorization
{
Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope),
User = MvcApplication.LoggedInUser,
CreatedOn = DateTime.UtcNow,
});
MvcApplication.DataContext.SaveChanges();
response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name);
}
else
{
response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest);
}
return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
}
Everytime the program reaches this line:
this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
The system throws an exception which I have researched with no success. The exception is the following:
Only parameterless constructors and initializers are supported in LINQ to Entities.
The stack trace: http://pastebin.com/TibCax2t
The only thing I've done differently from the sample is that I used entity framework's code first approach, an I think the sample was done using a designer which autogenerated the entities.
Thank you in advance.
If you started from the example, the problem Andrew is talking about stays in DatabaseKeyNonceStore.cs. The exception is raised by one on these two methods:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc());
return matches.FirstOrDefault();
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
return from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
}
I've resolved moving initializations outside of the query:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select key;
var match = matches.FirstOrDefault();
CryptoKey ck = new CryptoKey(match.Secret, match.ExpiresUtc.AsUtc());
return ck;
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select key;
List<KeyValuePair<string, CryptoKey>> en = new List<KeyValuePair<string, CryptoKey>>();
foreach (var key in matches)
en.Add(new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())));
return en.AsEnumerable<KeyValuePair<string,CryptoKey>>();
}
I'm not sure that this is the best way, but it works!
It looks like your ICryptoKeyStore implementation may be attempting to store CryptoKey directly, but it's not a class that is compatible with the Entity framework (due to not have a public default constructor). Instead, define your own entity class for storing the data in CryptoKey and your ICryptoKeyStore is responsible to transition between the two data types for persistence and retrieval.

Resources