Setting up data for Mockito - spring

I am unit testing my spring Rest API and I have had joy mocking my create and retrieve methods using the following structure.
#Test
public void getAllUsersReturnsAListOfAllTheUsersInJSONFormat() throws Exception {
List<User> users = new ArrayList<>();
users.add(new User("DelBoy"));
users.add(new User("Rodney_Trotter"));
users.add(new User("Uncle.Albert"));
Mockito.when(service.getAllUsers()).thenReturn(users);
mvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.hasSize(3)))
.andExpect(jsonPath("$[0].username", Matchers.equalTo("DelBoy")))
.andExpect(jsonPath("$[1].username", Matchers.equalTo("Rodney_Trotter")))
.andExpect(jsonPath("$[2].username", Matchers.equalTo("Uncle.Albert")));
}
However, I am trying to create a test for my Update and Delete methods. When I mock the methods they never behave as expected because there is no data to update or delete. After extensive research online I cannot find any information pointing to resolving this issue. My current attempt is the following code.
#Test
public void updateUserUpdatesAUserUponSuccess() throws Exception {
User updatedUser = new User(UUID.fromString("da3f6cae-9126-407b-a1ea-093bdac72434"), "Trigger");
Mockito.when(service.updateUser(updatedUser)).thenReturn(true);
Mockito.when(validator.validateUsername(updatedUser.getUsername())).thenReturn(true);
Mockito.when(validator.validateUUID(updatedUser.getUserId().toString())).thenReturn(true);
String str = mvc.perform(put("/api/users/da3f6cae-9126-407b-a1ea-093bdac72434/TriggersBroom"))
.andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
System.out.println(str);
}
I am not sure how to have user data mocked so that when I make a PUT request it can update the user at the hex Id specified to a different username ("trigger" being the username). How I would like this to work is to have a small set of user objects that I can update when I mock my updateUser function so I can test the update user route actually updates a record. Currently it returns false because nothing is being updated but it should return true as I have tested manually in my development environment outside of unit testing and it works.
Note:
The println was my was of checking what was actually returned and it was false.

How I would like this to work is to have a small set of user objects that I can update when I mock my updateUser function so I can test the update user route actually updates a record
This is because you write:
User updatedUser = new User(UUID.fromString("da3f6cae-9126-407b-a1ea-093bdac72434"), "Trigger");
Mockito.when(service.updateUser(updatedUser)).thenReturn(true);
Then you can see the updatedUser is not the same instance as the one you gonna call in the real service, it's just a instance you created above.
To mock this, you have 2 ways:
If you can get the exactly same instance as the one you gonna call in real service, it will return true for you.
You can use Mockito.eq(updatedUser) to mock. E.g. Mockito.when(service.updateUser(Mockito.eq(updatedUser))).thenReturn(true);
But then you need to remember to override the equals() method for class User. Then if you modify the method equals(), you need to update hashCode() as well

Related

Spring MVC test post method with controller redirect

I have a test:
#Test
public void shouldAddCompany() throws Exception {
mockMvc.perform(post("/companies")
.param("name", "companyName"))
.andExpect(model().attribute("company",
hasProperty("name", is("companyName"))));
}
and my controller method looks like that:
#PostMapping("/companies")
public String displayCompaniesPost(#ModelAttribute Company company) {
companyService.save(company);
return "redirect:/companies";
}
How can i check company attribute in test? There is a problem because of redirect and status 302.
java.lang.AssertionError: Model attribute 'company'
Expected: hasProperty("name", is "companyName")
but: was null
I think it occurs because controller is going to GET method because of redirection. When I remove this redirection everything is ok, but I don't want to remove that redirection.
EDIT (GetMapping):
#GetMapping({"/", "/companies"})
public String displayCompanies(Model model) {
model.addAttribute("company", new Company());
List<Company> companies = companyService.findAll();
model.addAttribute("companies", companies);
return "companies";
}
I thought the problem is because of addding attribute with the same name in getMapping, but when I removed it, it still doesn't work.
You need to modify your approach. If you POST to a controller method, and it returns a Redirect you will have no ability to access any model information set by that controller, it just returns an HTTP 302 with a Location Header to the client telling it the new url to go to (in this case GET /companies). If this is a strictly Unit test, that is the extent of what you can test for this method.
I would consider instead treating this as an integration test, and change your test to have two separate steps:
POST /companies and validate that the response is the expected redirect
GET /companies and validate that the list of companies returned contains the new company you posted in step 1

Calling TableController.Lookup() from one controller on another controller fails

In an Azure Mobile App using the .NET backend, I need one controller to look up an entity handled by a second controller. For example, in the Todo Quickstart project from the Azure team, imagine adding a UserController which handles user management. In TodoItemController, I need to call UserController.GetUser(id) to check if a user is authorized to post a new TodoItem.
In TodoItemController.cs:
var userController = new UserController();
var user = userController.GetUser("12345");
if (user.IsAuthorized)
{
// Insert TodoItem
}
The above code throws an exception when TableController.Lookup() is called in UserController.GetUser(). The exception says that the request parameter cannot be null. My guess is that something is missing because I created the UserController myself, instead of it being created by the framework.
How can I make this work?
This appears to work in TodoItemController.cs:
var context = new todoProjectContext();
var userDomainManager = new EntityDomainManager<User>(context, Request);
var user = userDomainManager.Lookup(id).Queryable.FirstOrDefault();
if (user.isAuthorized)
{
// Insert item
}
Not sure it's the best solution though.

How to store PreRequestFilter information in AuthUserSession

I am building a web service using ServiceStack which has to support multiple vendors. The web service provides largely the same functionality to all vendors with some exceptions here and there.
In order to re-use as much functionality as possible I have come up with the following URL scheme:
http://localhost/brand1/templates
http://localhost/brand2/templates
"brand1" and "brand2" are not services but "templates" is. The Templates service's request DTO's will have a property called "Brand" like so:
[Route("/{Brand}/templates", "GET")]
public class GetTemplates
{
public Brand Brand { get; set; }
}
So in the Templates service I know which brand I am dealing with. This scheme works well.
What I cannot figure out though is this. The user of the service has to be authenticated and I cannot figure out how to handle the redirection of the service after the user has been authenticated since I have to pass along the brand information. I have created my own CustomAuthProvider class that inherits CredentialsAuthProvider. In the TryAuthenticate method I can set the authService.GetSession().ReferrerUrl property to the correct brand if I know what it was.
The only way I have found so far to get this information is to register a PreRequestFilter. My thinking here was that since the URL (e.g. http://localhost/brand1/templates) contains the brand I can store it in my own AuthUserSession class. I can't figure out how to do this. I have a "SessionFactory" method that I pass to the AuthFeature constructor. But what should I do in there? How do I get to the brand that I've obtained in the PreRequestFilter? Is it safe to store it in a field of the AppHost? I think not because of concurrency issues. How do I tie the PreRequestFilter to the SessionFactory method?
I hope I am explaining my problem clearly enough?
I was overthinking the solution because I didn't realize that I had all the information I needed in the IServiceBase parameter of the TryAuthenticate method of the CredentialsAuthProvider class.
In the end I came to the following solution:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService,
string userName, string password)
{
var session = authService.GetSession();
var origQuery = authService.Request.UrlReferrer.Query;
session.ReferrerUrl = "/error";
var queryString = origQuery.Substring(10); // strip "redirect="
var decodedUrl = HttpUtility.UrlDecode(queryString);
if (!string.IsNullOrWhiteSpace(decodedUrl))
{
var query = new Uri(decodedUrl);
session.ReferrerUrl = query.AbsolutePath;
}
return DoAuthentication(userName, password);
}
}
The different places where you can set the Url to redirect to during ServiceStack Authentication, in order of precedence are:
The Session.ReferrerUrl Url if it's populated
The Continue QueryString, FormData param when making the request to /auth (i.e Authenticate.Continue property)
The HTTP Referer HTTP Header
The CallbackUrl of the current AuthProvider used

ZF2: Injecting Session management into a service

I'm familiar with how to use the Session in ZF2, e.g.
$user_session = new Container('user');
$user_session->username = 'JohnDoe';
This is fine, but if I'm trying to persist session data in one of my business logic services I'd strongly prefer to inject a session management object/service into my service's constructor, like in this pseudocode:
class BusinessSvc{
protected $sessionSvc;
function __construct($sessionSvc){
$this->sessionSvc = $sessionSvc;
}
public function doBusinessLayerStuff(){
... do stuff ...
$this->sessionSvc->store('lastOrderNumber', '1234');
... do stuff ...
}
}
I would think the framework would provide this functionality, but I can't find it anywhere. I could always write my own, but didn't want to reinvent the wheel.
The answer was a lot simpler than I realized. Once instantiated, a Container instance itself can be injected into the business service and provide it with access to the session. If using phpunit to later test the service, the object could be mocked with an array or an instance of ArrayObject.
In Module.php's getServiceConfig method:
'MyModule\Service\BusinessService' => function($sm) {
// Container doesn't need to use this name but it seems sensible.
$container = new Container('MyModule\Service\BusinessService');
return new Service\BusinessService($container);
},

Grails + RESTful URL mapping + Filters + Routes

Member have many jobs. A member can add, delete or update Jobs. Currently there are actions (add, delete or update) defined in a controller which are called through jQuery.ajax(). We are sending job id and member id to perform the operation. Member id is necessary because there is a role admin who can modify the job on behalf of members, so we need to identify the member. But sending member id is dangerous as anyone can send the request by modifying the member id.
I know, we can add constraint do restrict that only admin can modify the jobs or a member can modify only his jobs. My question is, Do I need to add these constraints in the action of the controller or Is there any Grails way to do that. I have google, the same thing is handled in Ruby and Rails by using routes. And in grails I have skim through RESTful URL mapping, which is perhaps used for this purpose.
Can anyone points me to right direction, thanks. I am using Grails 2.1.1.
You can implement some realization of AbstractPersistenceEventListenerService to not allow perform actions with entity that constains id of not logged in user. Example:
class MultiTenantPersistenceEventListenerService extends AbstractPersistenceEventListenerService {
def springSecurityService
#Override
protected AbstractPersistenceEventListener createPersistenceEventListener(Datastore datastore) {
return new MultiTenantPersistenceEventListener(datastore)
}
}
class MultiTenantPersistenceEventListener extends AbstractPersistenceEventListener {
MultiTenantPersistenceEventListener(final Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
def entity = event.getEntityObject() // could be your Job domain entity
def user = springSecurityService.getCurrentUser() //current logged in user
if(entity.hasProperty('userId')){ // every job belongs to User
if(entity.userId != user.id){
throw new AccessDeniedException("Acces Denied !")
}
}
}
}
I'd recomment to use grails spring-security-plugin. There is a lot of information in web about plugin and it's easy configurable. Plugin allows you to perfrom controller's action in secure way. For example:
#Secured(['ROLE_USER'])
def followAjax = { ... }
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def personal = { ... }
For more information - plugin and spring-security with grails.
You can use Authorize attribute to authorize the user,
e.g
[CustomAuthorize(Roles=SiteRoles.Admin|SiteRoles.HelpDesk)]
public ActionResult Index()
{
return View();
}
This is a nice approach for making website secure.
go through these link, this will help you.
custom authorization with asp.net mvc
asp.net mvc authorization

Resources