Why is this giving me AssertationError? - java

I have the following test :
#Test
public void deleteUser(){
User user = new User("admin","admin");
service.createUser(user);
service.deleteUser(1);
assertTrue("Check that user is deleted: ", user.getId() < 1);
}
But it gives me AssertationError.
Why can I not do like that?
I create my user and then wanna test that I am able to delete the newly created user.
My delete method is just deleting from a hashmap the user.
Map<Long, User> users = new HashMap<Long, User>();
protected static long nextId = 0;
#Override
public long createUser(User user) {
user.setId(getNextId());
users.put(user.getId(), user);
return user.getId();
}
#Override
public void deleteUser(long id) {
users.remove(id);
}
Can somebody explain this to me?

Instead of accessing the User object, that you still have the reference to (independent of whether it's deleted), you should implement a method, that checks, whether a user is present in the class of your service variable:
public boolean containsUser(long userId) {
return users.containsKey(userId);
}
And then assert like so:
assertFalse("Check that user is deleted: ", service.containsUser(1L));

When you delete user from Map, you do nothing with user.id. That's why your assertion fails.
One way to change id when deleting
#Override
public void deleteUser(long id) {
User deletedUser = users.remove(id);
deletedUser.setId(-1);
}
Another (and better) way is to change test:
#Test
public void deleteUser(){
User user = new User("admin","admin");
long id = service.createUser(user);
service.deleteUser(id);
assertFalse("Check that user is deleted: ", service.hasUser(id));
}

Your test does not make any sense - you want to check if the user is deleted from the service, but instead you are checking the value of the Id property of the user object (which is null, or set to some value - you did not provide any code). As some users already suggested, you need to check if the user is actually contained within your service. Also, are you doing something inside your getNextId() method? If that is simply getter for your nextId variable, every single user you create will have Id set to 0 (but maybe you wanted it that way, who knows). Is there some code within getNextId that actually sets the value to something else?

Related

Function to check if user is allowed to do something and if no get reason why

I need to check if user is allowed to cancel appointment. Right now i first call service method which return boolean and if it is false then I call another method which returns reason in String. It is working but I think it's ugly. Do you have any ideas how can I improve this? Or maybe this approach is okay?
AppointmentService:
public boolean isUserAllowedToCancelAppointment(int userId, int appointmentId) {
User user = userService.findById(userId);
Appointment appointment = findById(appointmentId);
// only scheduled appointments can be canceled
if(!appointment.getStatus().equals("scheduled")){
return false;
}
// other conditions...
}
public String getCancelNotAllowedReason(int userId, int appointmentId) {
User user = userService.findById(userId);
Appointment appointment = findById(appointmentId);
if(!appointment.getStatus().equals("scheduled")){
return "status";
// other conditions and reasons...
}
Controller:
#GetMapping("/{id}")
public String showAppointmentDetail(#PathVariable("id") int appointmentId, Model model, #AuthenticationPrincipal CustomUserDetails currentUser) {
if (appointmentService.isUserAllowedToCancelAppointment(currentUser.getId(), appointmentId)) {
model.addAttribute("allowCancel", true);
} else {
model.addAttribute("allowCancel", false);
model.addAttribute("cancelNotAllowedReason", appointmentService.getCancelNotAllowedReason(currentUser.getId(), appointmentId));
}
}
Create an enum of possible issues:
enum Issue {TOO_LATE, NOT_SCHEDULED, ... }
And then create a single validation method which returns a Set<Issue>:
public Set<Issue> validate(int userId, int appointmentId) { ... }
Then you can check the different cases and if they apply add the Issue to the set:
Set<Issue> issues = EnumSet.noneOf(Issue.class);
if( not scheduled ) {
issues.add(Issue.NOT_SCHEDULED);
}
if( too late ) {
issues.add(Issue.TOO_LATE);
}
return issues;
Then at the call site you can check if issues.isEmpty():
Set<Issue> issues = appointmentService.validate(userId, appointmentId);
model.addAttribute("allowCancel", issues.isEmpty());
model.addAttribute("cancelNotAllowedReason", issues);
You are making two calls, while you should only make one.
This is indeed not recommended.
Drop the boolean method, and keep something like:
public String getCancelNotAllowedReason(int userId, int appointmentId) {
User user = userService.findById(userId);
Appointment appointment = findById(appointmentId);
if(!appointment.getStatus().equals("scheduled")){
return "not yet scheduled";
}
if ( appointment.isDateTooClose()) {
return "Too late to cancel";
}
// other conditions and reasons...
return "Valid";
}
In the calling class:
if ( service.getCancellNotAllowedReason(1, 1).equals("Valid")) {
//cancel
} else {
// show information message
}
It might be better, though, to return a List<String> of reasons. Otherwise, your client might fix the first issue, and assume he can cancel than, just to get stuck on the next issue.
getCancelNotAllowedReason() can simply return null when a cancel is allowed. No need for a separate check function.
String reason = appointmentService.getCancelNotAllowedReason(currentUser.getId(), appointmentId);
model.addAttribute("allowCancel", reason == null);
model.addAttribute("cancelNotAllowedReason", reason);

Data is autodeleted from in-memory database

I use HSQLDB for testing purpose. The problem is that when I add some data in init() method, then I can get that data only from the test which did run first.
#Before
public void init() {
if(isRun)
return;
isRun = true;
Role role = new Role();
role.setId(1);
role.setType("User");
roleDAO.save(role);
User user = new User();
user.setCredits(1000);
user.setEmail("User#test.com");
user.setUsername("User");
user.setPassword("qwerty");
user.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user);
User user2 = new User();
user2.setCredits(1000);
user2.setEmail("User2#test.com");
user2.setUsername("User2");
user2.setPassword("qwerty");
user2.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user2);
}
#Test
public void findUserByIdTest() {
User user = userDAO.findByUsername("User");
assertEquals(userDAO.findById(user.getId()), user);
}
#Test
public void addUserTest() {
User user = new User();
user.setCredits(1000);
user.setEmail("Antony#test.com");
user.setPassword("qwerty");
user.setUsername("Antony");
user.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user);
assertEquals(userDAO.findByUsername("Antony"), user);
}
#Test
public void updateUserTest() {
User user = userDAO.findByUsername("User");
user.setCredits(0);
assertEquals(userDAO.findByUsername("User").getCredits(), (Integer) 0);
}
#Test
public void removeUserTest() {
userDAO.remove(userDAO.findByUsername("User"));
assertNull(userDAO.findByUsername("User"));
}
So happens that removeUserTest() method always runs first and when I findAll() data then I see the data I set in init() method. After that, others test methods run but if I do findAll() there, it just returns nothing meaning no data exists.
In addition, I have set hibernate.hbm2ddl.auto=create.
What am I missing here? Why I can get data in the first running method but in others the data just disappears.
It's expected: Spring repository tests are transactional and the transaction is rollbacked at the end of each test by default.
Even if you choose not to rollback, every test should be independant from the others, and should be able to run alone. You should not rely on the execution order either. Your findUserByIdTest() would fail if removeUserTest() runs first.
So, start by cleaning the database and to insert the test data before each test. If you let Spring rollback after each test, cleaning is not necessary, but you should still insert the test data before each test.
Incrementing IDs should not be a problem: you just need to stire the created entities or their IDs in fields of the test, and refer to these entities and their IDs instead of using hard-coded IDs in the test.

How to store specific object in HashMap with iterating id as key

I am working on on a program. I was storing Users in a ArrayList, so I had a UserCollection class which is acting as the storage class for the Users. But seeing as the UserCollection is thought of as a 'database' each user entry in the database should have a unique id. Initially I had a userID as a field in the User class but now I'm trying to handle the id part in the UserCollection. If I were to use a hashmap, where the key would be the id, the value being the User how would I go on about iterating the id so that every time a new User is stored into the hashmap, they key keeps iterrating from 1 to n amount of users.I'm also using CRUD methods to store/remove/update etc the Users.
public class UserCollection{
Map<Integer, User> userMap = new HashMap<Integer,User>();
public User create(User user){
userMap.put(??,user) // not sure how to iterate the id or what to put in it
return user;
}
public User read(Integer keyID){
if(userMap.containsKey(keyID)){
return userMap.get(keyID); //something definitely wrong
}
}
//Other remaining CRUD methods after.
}
Originally I just had an ArrayList which held Users. But Because I realized in a database Users will have unique id's now I'm confused how I would handle them. If i handle them in the HashMap do I still need to have a userID field in the User class ?
You have asked a couple of questions here. I'll take each of them in turn:
How can I ensure that each user has a unique ID?
The simplest way to do this is to have a static field that keeps track of the largest generated id:
class User {
private static int largestID = 0;
private final int id = largestID++;
public int getID() {
return id;
}
...
}
This works but has plenty of problems with it. As soon as you store users & restart the programme, or want to reuse ids, it needs changing.
Another approach is to just find the largest id for existing customers from your collection. The following sample code uses Java 8:
class UserCollection {
private final Map<Integer,User> users = new HashMap<>();
public int nextID() {
return users.keySet().stream()
.mapToInt(n -> n).max().orElse(-1) + 1;
}
}
This is inefficient but probably good enough for a lot of applications.
Do I need to store the ID in the User class?
You have two options. Either you store it in the class and provide a mechanism for getting the ID (as above). Or you ensure that everything that deals with users stores and returns IDs, not references to objects. This allows the client of the method to then access the User using the ID.
Both of these are legitimate solutions. If you use the first (storing the ID in the class) then you should change your method for adding a User to your collection:
class UserCollection {
public void addUser(User user) {
users.put(user.getID(), user);
}
}
If you use the second, the ID field must be final because clients are relying on it not changing.
You could do the following to ensure that your Users have a unique ID for the life of the class.
public class UserCollection
{
private static int id = 0;
private static final Object lock = new Object();
private Map<Integer, User> userMap = new HashMap<Integer,User>();
public User create (User user)
{
// only add one user at a time to the map
synchronized (lock)
{
id++;
userMap.put(id, user);
}
return user;
}
// Rest of the class
}

Pattern for persisting data in Realm?

My issue is how to organize the code. Let say I have a User class
public class User extends RealmObject {
#PrimaryKey
private String id;
#Required
private String name;
public User() { // per requirement of no args constructor
id = UUID.randomUUID().toString();
}
// Assume getter & setter below...
}
and a Util class is needed to handles the save in an asynchronous manner since RealmObjects cannot have methods other than getter/setter.
public class Util {
public static void save(User user, Realm realm) {
RealmAsyncTask transaction = realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealm(user); // <====== Argument needs to be declared final in parent method's argument!
}
}, null);
}
}
The intention is to put save() in a Util class to prevent spreading similar save code all over the code-base so that every time I wanted to save I would just call it as such:
User u = new User();
u.setName("Uncle Sam");
Util.save(u, Realm.getDefaultInstance());
Not sure if this affects performance at all, but I was just going to save all fields overwriting what was there except for the unique id field every single time.
The problem is that I now need to set the "user" argument as final in the Util.save() method, which means I cannot pass in the object I need to save other than once.
Is there a different way of handling this? Maybe a different pattern? Or am I looking at this all wrong and should go back to SQLite?
Why is it a problem to set public static void save(final User user, Realm realm) ? It just means you cannot reassign the user variable to something else.
That said, the existence of a save() method can be a potential code smell as you then spread the update behaviour across the code base. I would suggest looking into something like the Repository pattern (http://martinfowler.com/eaaCatalog/repository.html) instead.
Realm is actually working on an example showing how you can combine the Model-View-Presenter architecture with a Repository to encapsulate updates which is a good pattern for what you are trying to do here. You can see the code for it here: https://github.com/realm/realm-java/pull/1960

How to test deletion in JUnit (Play Framework)?

I need to make a JUnit test that checks whether it is possible to delete something from the database. I'm using the Play 2.1 Framework with an in-memory database.
I tried assertNull(...), but that failed. I then tried assertNotNUll(...) and the test passes, but I'm not sure this is the best way to do it or that it can even confirm deletion. Is there a better way to check if an item has been deleted? Should I look up the object and expect an error?
Here's my code (I also have some #BeforeClass and #AfterClass code, but it's no relevant to my question):
#Test
public void UserDelete(){
// Test ID: 3
// creating a new user
User user = new User();
user.id = (long) 4;
user.facebookId = "0000004";
user.email = "test4#gmail.com";
user.name = "name4";
user.save();
// deleting the user
user.delete();
// checking deletion
assertNotNull(user);
}
In general you usually have to do something like this. Of course this is a crude example but it points out that you should use some persistence solution like JPA to persist your domain objects.
#Test(expected = WhateverObjectNotFoundException.class)
public void removeUserTest(){
User u = UserFactory.createTestUser();
Long id = myEntityManager.persist(u);
assertNotNull(id);
myEntityManager.remove(u);
myEntityManager.findById(id);
}
In my opinion the User shouldn't be responsible for its lifecycle since it does not make sense to ask an object to delete itself hence your question is somewhat paradox.
This solution later can be generalized so you won't have to write it all over again when you test for the same kind of behavior.
You should insert new object in DB, check that is was inserted, delete it and check that it was deleted. Most obvious way is to use select count(*) to get number of rows.
public class ApplicationTest extends WithApplication {
#Before
public void setup() {
start(fakeApplication(inMemoryDatabase("default-test"), fakeGlobal()));
}
#Test
public void UserModify() {
// create user (User extends Model)
User user = new User();
user.setId(1);
user.setName("name1");
user.save();
int rowCount = Ebean.find(User.class).where().eq("id", 1).findRowCount();
assertEquals(1, rowCount);
user.delete();
rowCount = Ebean.find(User.class).where().eq("id", 1).findRowCount();
assertEquals(0, rowCount);
}
}

Categories