I can't mock property of class - unit-testing

I've just started using spock and I am facing one issue..
public class UserAuthentication {
private UserDAO userDao;
public boolean authenticateUser(String email, String password){
User user = userDao.findUserByEmail(email);
if(password.equals(user.getDecodedPassword())){
return true;
}
return false;
}
}
public interface UserDAO {
User findUserByEmail(String login);
void saveUser(User user);
}
public class User {
private String email;
private String decodedPassword;
public User(String email, String decodedPassword) {
this.email = email;
this.decodedPassword = decodedPassword;
}(...)
Unfortunately my test throw NullPointerException:
import java.text.SimpleDateFormat
import spock.lang.Specification
class UserAuthenticationTest extends Specification {
def "Authenticating correct user" () {
setup:
def email = "email#email.com"
def password = "qwerty1234"
def userDao = Mock(UserDAO)
userDao.findUserByEmail(email) >> new User(email, password)
def userAuthenticator = new UserAuthentication()
userAuthenticator.setUserDao(userDao)
when:
def result = userAuthenticator.authenticateUser(email, password)
then:
1 * userDao.findUserByEmail(email)
result == true
}
}
I got the exception because mock doesn't work when is invoked (userDao.findUserByEmail(email); in UserAuthentication class).
Anyone have some idea why?

When you both mock and verify the returned (from mock) expression should be placed under then block. Here are the docs and below You can find corrected code:
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
import java.text.SimpleDateFormat
class UserAuthenticationTest extends Specification {
def "Authenticating correct user" () {
setup:
def email = "email#email.com"
def password = "qwerty1234"
def userDao = Mock(UserDAO)
def userAuthenticator = new UserAuthentication()
userAuthenticator.userDao = userDao
when:
def result = userAuthenticator.authenticateUser(email, password)
then:
1 * userDao.findUserByEmail(email) >> new User(email, password)
result == true
}
}
public class UserAuthentication {
UserDAO userDao;
public boolean authenticateUser(String email, String password){
User user = userDao.findUserByEmail(email);
return password.equals(user.getDecodedPassword());
}
}
public interface UserDAO {
User findUserByEmail(String login);
void saveUser(User user);
}
public class User {
private String email;
private String decodedPassword;
public User(String email, String decodedPassword) {
this.email = email;
this.decodedPassword = decodedPassword;
}
public String getDecodedPassword() {
return decodedPassword;
}
}

Related

How get token from headers to test my controller by mocking the service class

public class AdditionDto
{
public int HttpCode {get; set:}
public string UserName {get; set:}
public int Total {get; set:}
}
public interface IAddtionService
{
AdditionDto AddingTwoNumbers(int input1, int input2, string userName);
}
public class AdditionService : IAdditionService
{
public AdditionDto AddingTwoNumbers(int input1, int input2, string userName)
{
AdditionDto addDto = new AdditionDto()
{
httpCode = 200,
UserName = userName,
Total = input1 + input2
}
return addDto;
}
}
With a controller like this:
public class AdditionController : ControllerBase
{
private readonly IAddtionService _additionService;
public AdditionController(IAddtionService additionService)
{
_additionService = additionService;
}
[HttpGet]
[Authorize(Roles = "Admin")]
[Route("AddtionOfTwoNumbers")]
public IActionResult AddTwoNumbers(int input1, int input2)
{
if (ModelState.IsValid)
{
var token = HttpContext.Request.Headers["Authorization"].ToString();
var tokenbearer = token.Split(' ');
var handler = new JwtSecurityTokenHandler();
var decodedtoken = handler.ReadJwtToken(tokenbearer[1]);
string user = decodedtoken.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name").FirstOrDefault().ToString();
var usr = user.Split(":");
string userName = usr[2].Trim();
var result = _additionService.AddingTwoNumbers(input1, input2,userName);
if (result.Httpcode == 200)
return Ok(result);
else
return StatusCode(500, result);
}
else
return BadRequest();
}
}
When i am trying to conduct xunit test on this api I am getting null at header level.
also I need to mock service method that is also not happening. mostly it is showing null exception even I have passed token in the headers also then I am facing mocking issue at the service method level. could you please help me to mock my service method to test that api through xunit framework....

Add custom SQL column in register

environment: vs2017, .core net 2.1, default .core project with MVC
I try to add NickName column store in SQL DB, i had update DB and also add NickName column in the input model. it succeeds to show input the NickName option in the register page but fault to write into SQL DB after clicks register(and other work as usual).
after override IdentityUser it does not work.
add/chg code in Register.cshtml.cs:
public class CustomUserproperties : IdentityUser
{
public string NickName { get; set; }
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
//here is where i change.
var user = new CustomUserproperties { UserName = Input.UserName, Email = Input.Email, NickName = Input.NickName };
var result = await _userManager.CreateAsync(user, Input.Password);
what could i do else?
Here is a working demo, you could refer to create a new or check the difference between your old one.
1.Modify ApplicationDbContext and Add-migration , update-database
public class ApplicationDbContext : IdentityDbContext<CustomUserproperties>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
2. Scaffold the Identity with the above ApplicationDbContext , then you could get RegisterModel like below:
public class RegisterModel : PageModel
{
private readonly SignInManager<CustomUserproperties> _signInManager;
private readonly UserManager<CustomUserproperties> _userManager;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<CustomUserproperties> userManager,
SignInManager<CustomUserproperties> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
public class InputModel
{
[Required]
[Display(Name = "NickName")]
public string NickName { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var user = new CustomUserproperties { UserName = Input.Email, Email = Input.Email , NickName = Input.NickName };
var result = await _userManager.CreateAsync(user, Input.Password);
...
}
}
}
3.Change the ConfigureServices in StartUp.cs
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<CustomUserproperties>()
.AddEntityFrameworkStores<ApplicationDbContext>();
4._LoginPartial.cshtml
#inject SignInManager<CustomUserproperties> SignInManager
#inject UserManager<CustomUserproperties> UserManager
Here is my project .

Grails 2.4.5 controller unit test verify transaction has rolled back

Here is a simple controller
class UserController {
#Transactional
def update() {
try {
....
throw new Exception("test transaction rollback")
...
} catch( e ) {
transactionStatus.setRollbackOnly()
respond "{ "status":"error" }"
}
}
}
Here is a unit test spec
#TestFor(UserController)
class UserControllerSpec extends Specification {
when:''
controller.update()
then:'verify that transaction has been rolled back'
// it fails with missing property, whats the best way to check that it was rolled back ?
controller.transactionManager.transactionRolledBack == true
}
whats the best way to test that the transaction has been rolled back ?
After #BurtBeckwith suggestion tried an integration spec.
// Domain User.groovy
class User { String firstName; String lastName }
// UserController.groovy
class UserController {
static responseFormats = ['json', 'xml']
static allowedMethods = [update: 'PUT']
#Transactional
def update( UserCommand cmd ) {
User m = User.get(id)
m.firstName=cmd.firstName
m.lastName=cmd.lastName
m.save(failOnError:true,flush:true)
transactionStatus.setRollbackOnly()
}
}
class UserCommand { Long id; String firstName; String lastName }
// IntegrationSpec UserControllerIntegrationSpec.groovy
import grails.test.spock.IntegrationSpec
class UserControllerIntegrationSpec extends IntegrationSpec {
def controller
def sessionFactory
def setup() {
controller = new UserController()
}
void "test transaction rollback"() {
given:'a user'
User u = new User(firstName:'oldFirstName',lastName:'oldLastName')
u.save(flush:true,failOnError:true)
controller.request.method='PUT'
controller.request.contentType = "application/json"
controller.request.content = '{"id":u.id,"firstName":"newFirstName","lastName":"newLastName"}'.getBytes()
when:'an update that rollsback is called'
controller.update()
// clear so that we do not get data from cache.
sessionFactory.currentSession.flush()
sessionFactory.currentSession.clear()
then:'we should still see old data'
User u2 = User.get(u.id)
// The following fails, u.firstName has 'newFirstName' which is wrong on rollback
u2.firstName == 'oldFirstName'
u2.lastName == 'oldLastName'
}
}
// DataSource.groovy
test {
dataSource {
url = "jdbc:mysql://localhost/starter_app_test"
driverClassName = "com.mysql.jdbc.Driver"
pooled = true
properties {
...
defaultAutoCommit=false
}
}
}
Any ideas why in integration test data seems to get persisted even when we rollback ?

CognitoCachingCredentialsProvider (Android) - how to logout and remove cached credentials

I'm using the developer-authenticated technique for implementing this class, as described here. So far, I've been able to implement this class and build a framework in which I check CognitoCachingCredentialsProvider.getCachedIdentityId() to see if a user has logged in (and therefore doesn't need to re-authenticate by entering an email and password). To do this, I'm using a series of static methods in a class called Util, since these only need to be instantiated once. This is what it looks like:
package com.pranskee.boxesapp;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.util.Log;
import com.amazonaws.auth.AWSAbstractCognitoIdentityProvider;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.cognito.*;
import com.amazonaws.regions.Regions;
public class Util {
private final static String TAG = "Util";
private static final String AWS_ACCOUNT_ID = {acct id};
private static final String COGNITO_POOL_ID = {pool id};
private static final String COGNITO_ROLE_AUTH = {auth arn};
private static final String COGNITO_ROLE_UNAUTH = {unauth arn}
private static CognitoCachingCredentialsProvider sCredProvider;
private static UserIdentityProvider sIdProvider;
private static CognitoSyncManager sSyncManager;
private Util() {
}
public static CognitoCachingCredentialsProvider getCredProvider(
Context context) {
if (sCredProvider == null) {
if (sIdProvider == null) {
CognitoCachingCredentialsProvider tmpProvider = new CognitoCachingCredentialsProvider(
context.getApplicationContext(), AWS_ACCOUNT_ID,
COGNITO_POOL_ID, COGNITO_ROLE_UNAUTH,
COGNITO_ROLE_AUTH, Regions.US_EAST_1);
if (tmpProvider.getCachedIdentityId() != null) {
sCredProvider = tmpProvider;
} else {
sCredProvider = null;
}
} else {
sCredProvider = new CognitoCachingCredentialsProvider(
context.getApplicationContext(), sIdProvider,
COGNITO_ROLE_UNAUTH, COGNITO_ROLE_AUTH);
}
}
return sCredProvider;
}
public static UserIdentityProvider getIdentityProvider(Context context,
String email, String pwd) {
if (sIdProvider == null) {
sIdProvider = new UserIdentityProvider(AWS_ACCOUNT_ID,
COGNITO_POOL_ID, context.getApplicationContext(), email,
pwd);
Map logins = new HashMap();
logins.put({Developer Provider Name}, sIdProvider.getToken());
sIdProvider.setLogins(logins);
}
return sIdProvider;
}
public static boolean isLoggedIn(Context context) {
if (getCredProvider(context) == null) {
return false;
}
return true;
}
private static CognitoSyncManager getSyncManager(Context context) {
if (sSyncManager == null) {
sSyncManager = new CognitoSyncManager(
context.getApplicationContext(), Regions.US_EAST_1,
sCredProvider);
}
return sSyncManager;
}
protected static class UserIdentityProvider extends
AWSAbstractCognitoIdentityProvider {
private Context context;
private String email;
private String password;
public UserIdentityProvider(String accountId, String identityPoolId,
Context c, String em, String pwd) {
super(accountId, identityPoolId);
context = c;
email = em;
password = pwd;
}
#Override
public String refresh() {
try {
ServerCommunicator server = new ServerCommunicator(context);
//this is a server call, which makes the call GetOpenIdTokenForDeveloperIdentityRequest after I authenticate the user and send AWS my user's token
String response = server.initUserLoginAsyncTask()
.execute(email, password).get();
JSONObject responseJSON = new JSONObject(response);
String identityId = responseJSON.getString("id");
String token = responseJSON.getString("token");
this.setToken(token);
this.setIdentityId(identityId);
update(identityId, token);
return token;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
public String getProviderName() {
return {Developer Provider Name};
}
}
}
Now, I want to also implement a Logout. I think what I'd need to do is remove the cached Identity Id somehow, but I'm not sure what the best method would be to do that. Or, maybe it's not that at all, and I need to do something differently entirely. Either way, I just want to implement the intended behavior of allowing a user to select to "Log Out" of my app, which causes Cognito to forget that that ID was logged into the Identity Pool and invalidates any attempt to establish an Identity ID again without going through my authentication process again.
Logout would be a two steps process, first you need to logout from the Identity Provider that authenticated your user (Amazon, Google, Facebook or your own) Instructions on how to do this are specific to your provider.
From the CognitoIdentity side, you need to tell the CredentialsProvider to clear all state and cache associated with your identity. Using Android SDK, you can call clear() on the CredentialsProvider (see http://docs.aws.amazon.com/AWSAndroidSDK/latest/javadoc/com/amazonaws/auth/CognitoCredentialsProvider.html)

Testing a Spring MVC controller method with Spring MockMvc* classes

I am trying to test the following Spring mvc controller method:
#RequestMapping(value = "/preferences/email", method = RequestMethod.POST, produces = "text/html")
public String modifyEmail(#ModelAttribute #Validated({ Validation.EmailModification.class }) EmailInfo emailInfo, BindingResult bindingResult, Model model, Locale locale) {
Member member = memberService.retrieveCurrentMember();
if (!preferencesService.isEmailAvailable(emailInfo.getEmail())) {
if (member.getEmail().equals(emailInfo.getEmail())) {
bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.same_email", null, locale)));
} else {
bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.email_already_used", null, locale)));
}
}
if (bindingResult.hasErrors()) {
model.addAttribute("emailInfo", emailInfo);
return "preferences";
}
preferencesService.modifyEmail(member, emailInfo.getEmail());
return "redirect:/preferences/email";
}
Here is the EmailInfo bean:
#RooEquals
#RooJavaBean
public class EmailInfo {
#NotNull(groups = { Validation.EmailModification.class })
#Pattern(regexp = "^[_a-z0-9-]+(\\.[_a-z0-9-]+)*#[a-z0-9-]+(\\.[a-z0-9-]+)+$", groups = { Validation.EmailModification.class })
private String email;
private boolean activated;
private String token;
}
Here is the test class:
#ContextConfiguration
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class PreferenceControllerTest {
#Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
#Autowired
private MemberService memberService;
#Autowired
private PreferencesService preferencesService;
#Autowired
private MemberRepository memberRepository;
#Autowired
private SigninService signinService;
#Autowired
private MessageSource messageSource;
#Before
public void setup() {
mockMvc = webAppContextSetup(ctx).build();
Member currentMember = new Member();
currentMember.setEmail("currentMember#example.com");
when(memberService.retrieveCurrentMember()).thenReturn(currentMember);
when(preferencesService.isEmailAvailable("notAvailable#example.com")).thenReturn(Boolean.FALSE);
}
#Test
public void test() throws Exception {
mockMvc.perform(post("/preferences/email")//
.param("email", "newEmail#example.com"))//
.andDo(print()).andExpect(model().attributeHasNoErrors("emailInfo", "email"));
}
#Configuration
public static class testConfiguration {
#Bean
public PreferenceController preferenceController() {
return new PreferenceController();
}
#Bean
public PreferencesService preferenceService() {
return mock(PreferencesService.class);
}
#Bean
public MemberService memberService() {
return mock(MemberService.class);
}
#Bean
public MemberRepository memberRepository() {
return mock(MemberRepository.class);
}
#Bean
public SigninService signinService() {
return mock(SigninService.class);
}
#Bean
public MessageSource messageSource() {
return mock(MessageSource.class);
}
}
}
Curiously I get the following output:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /preferences/email
Parameters = {email=[newEmail#example.com]}
Headers = {}
Handler:
Type = com.bignibou.controller.PreferenceController
Async:
Was async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = preferences
View = null
Attribute = emailInfo
value = com.bignibou.controller.helpers.EmailInfo#9a56c123
errors = [Field error in object 'emailInfo' on field 'email': rejected value [null]; codes []; arguments []; default message [null]]
FlashMap:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = preferences
Redirected URL = null
Cookies = []
The test fails with the above output and I am not sure why. I expected the test to pass as the email address is available.
Can anyone please help?
edit 1:
The following is not working either:
#Before
public void setup() {
mockMvc = webAppContextSetup(ctx).build();
Member currentMember = new Member();
currentMember.setEmail("currentMember#example.com");
when(memberService.retrieveCurrentMember()).thenReturn(currentMember);
when(preferencesService.isEmailAvailable(eq("notAvailable#example.com"))).thenReturn(Boolean.FALSE);
when(preferencesService.isEmailAvailable(eq("newEmail#example.com"))).thenReturn(Boolean.TRUE);
}
edit 2:
I was able to get is to work with the above edit 1 plus the test below:
#Test
public void test() throws Exception {
mockMvc.perform(post("/preferences/email")//
.param("email", "available#example.com"))//
.andDo(print())//
.andExpect(model().attributeHasNoErrors("emailInfo"));
}
With this :
.param("email", "newEmail#example.com"))//
You are setting request parameter to the string value. However you have not shown your conversion from String to EmailInfo.
In your test you are checking the field of emailInfo called email.
I am not sure what this is for ?
when(preferencesService.isEmailAvailable("notAvailable#example.com")).thenReturn(Boolean.FALSE);
What is supposed to do, you have injected your preferenceService using autowired.
Updae to answer comment.
in your controller try
String email=emailInfo.getEmail();
if(!preferencesService.isEmailAvailable(email))){ instead of if (!preferencesService.isEmailAvailable(emailInfo.getEmail())) {
Not sure, just a possible solution
Or try
when(preferencesService.isEmailAvailable(eq("newEmail#example.com"))).thenReturn(Boolean.TRUE);
when(preferencesService.isEmailAvailable(eq("notAvailable#example.com"))).thenReturn(Boolean.FALSE);
Ae you using Mockito to implement mocking?
I am not 100% sure but here is How I understand your code.
when(preferencesService.isEmailAvailable("notAvailable#example.com")).thenReturn(Boolean.FALSE);
if preferencesService.isEmailAvailable returns true then you are forcefully returning false in mock exercise
so when in mock exercise preferencesService.isEmailAvailable will always return false.
Now in your Controller
if (!preferencesService.isEmailAvailable(emailInfo.getEmail())) {
if (member.getEmail().equals(emailInfo.getEmail())) {
bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.same_email", null, locale)));
} else {
bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.email_already_used", null, locale)));
}
}
If preferencesService.isEmailAvailable is false then ! make it true so code will always go inside if Block , and you will get Field Error, and hence Test fails.