In my Web tier I show a list of Tasks and for each task it shows how many TaskErrors it has. The tasks are fetched in a controller class this way:
public List<Task> getTasks () {
return taskEJB.findAll();
}
Task has a #OneToMany mapping with TaskErrors: a task can have multiple task errors.
When I delete a single TaskError, a controller in the Web tier calls TaskErrorFacade:remove(taskError). TaskErrorFacade is a stateless session bean. The code:
public void remove (TaskError taskError) {
entityManager.remove(entityManager.merge(taskError));
Task task = taskError.getTask();
task.deleteTaskError(taskError);
task = entityManager.merge(task);
}
Task:deleteTaskErrors(TaskError taskError) simply deletes the task from the List:
public void deleteTaskError (TaskError p_error) {
taskErrorCollection.remove(p_error); // gives true
}
This works. The Web tier shows a tabel with all the task and the number of Task Errors it has. The number drops by 1 after deleting a TaskError.
But... the following two implementations of TaskErrorFacade:remove(taskError) don't work: the tabel in the Web tier doesn't subtract 1 of the total Task Error count (however, they are deleted in the database):
public void remove (TaskError taskError) {
entityManager.remove(entityManager.merge(taskError));
Task task = taskError.getTask();
task = entityManager.merge(task); // the merge is done before the deletion
task.deleteTaskError(taskError);
}
And:
public void remove (TaskError taskError) {
entityManager.remove(entityManager.merge(taskError));
taskError.getTask().deleteTaskError(taskError); // no merge
}
Why are the two implementations above not working?
Edit: also important are the mappings of the relations. Task is mapped in TaskError this way:
#JoinColumn(name = "task_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Task task;
Related
1) Contextualization:
In order, to have a complete test-isolation-state in all test of my Test-Class;
I would like to have a new-instance-repository(DAO) for each individual test;
My Repository is a Interface, thats the why I can not simply instantiate that.
My Goal is:
Run all tests 'Parallelly', meaning 'at the same time';
That's the why, I need individual/multiple instances of Repository(DAO) in each test;
Those multiple instances will make sure that the tests' conclusion would not interfere on those that still is running.
Below is the code for the above situation:
1.1) Code:
Current working status: working, BUT with ths SAME-REPOSITORY-INSTANCE;
Current behaviour:
The tests are not stable;
SOMETIMES, they interfere in each other;
meaning, the test that finalize early, destroy the Repository Bean that still is being used, for the test that is still running.
public class ServiceTests2 extends ConfigTests {
private List<Customer> customerList;
private Flux<Customer> customerFlux;
#Lazy
#Autowired
private ICustomerRepo repo;
private ICustomerService service;
#BeforeEach
public void setUp() {
service = new CustomerService(repo);
Customer customer1 = customerWithName().create();
Customer customer2 = customerWithName().create();
customerList = Arrays.asList(customer1,customer2);
customerFlux = service.saveAll(customerList);
}
#Test
#DisplayName("Save")
public void save() {
StepVerifier.create(customerFlux)
.expectNextSequence(customerList)
.verifyComplete();
}
#Test
#DisplayName("Find: Objects")
public void find_object() {
StepVerifier
.create(customerFlux)
.expectNext(customerList.get(0))
.expectNext(customerList.get(1))
.verifyComplete();
}
}
2) The ERROR happening:
This ERROR happens in the failed-Tests:
3) Question:
How Can I create multiple instances of Repository
Even if, it being a Interface(does not allow instantation)?
In order, to have a COMPLETE TEST-ISOLATION
Meaning: ONE different instance of Repository in each test?
Thanks a lot for any help or idea
You can use the #DirtiesContext annotation on the test class that modifies the application context.
Java Doc
Spring documentation
By default, this will mark the application context as dirty after the entire test class is run. If you would like to mark the context as dirty after a single test method, then you can either annotate the test method instead or set the classMode property to AFTER_EACH_TEST_METHOD at your class level annotation.
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
When an application context is marked dirty, it is removed from the
testing framework's cache and closed; thus the underlying Spring
container is rebuilt for any subsequent test that requires a context
with the same set of resource locations.
In my project I have a component that displays a list of products in a specific group.
public class ProductListIncategoryViewComponent : ViewComponent
{
private IProductRepository productRepository;
public ProductListIncategoryViewComponent(IProductRepository repoprod)
{
productRepository = repoprod;
}
public IViewComponentResult Invoke(int priorityid)
{
MixProductView result = productRepository.SelectByCategory(priorityid);
return View(result);
}
}
Component input is groupID.
So I call the component twice to show the products of the two groups. for example:
#await Component.InvokeAsync("ProductListIncategory", new { priorityid = 3 })
#await Component.InvokeAsync("ProductListIncategory", new { priorityid = 4 }) //Error
I have an error when doing it two times in a row.
Cannot access a disposed object. A common cause of this error is
disposing a context that was resolved from dependency injection and
then later trying to use the same context instance elsewhere in your
application. This may occur if you are calling Dispose() on the
context, or wrapping the context in a using statement. If you are
using dependency injection, you should let the dependency injection
container take care of disposing context instances. Object name:
'KuteCoredbContext
but There is no Erro when calling the component once
#await Component.InvokeAsync("ProductListIncategory", new { priorityid = 3 })
or when call component by other groupid
#await Component.InvokeAsync("ProductListIncategory", new { priorityid = 4 })
I found the solution.
I needed to add this command to startup.cs after services.AddDbContext
services.AddDbContext<KuteCoredbContext>(option => option.UseSqlServer(Configuration["Data:KuteCore:ConnectionString"]));
services.AddTransient<KuteCoredbContext>();// <----add thos command
I've the following scenario:
Data will be created by the sender on the server.
If the receiver won't request the data within (for example) three days, the data should be deleted otherwise the receiver gets the data and after getting the data, the data will be deleted.
In other words:
The data should only exist for a limited time.
I could create a little jar-file which will delete the data manually, probably started as a cron-job. But i think, that that is a very bad solution.
Is it possible to create a trigger with JPA/Java EE that will be called after a specific time period? As far as i know trigger can only be called after/before insert, update, delete events. So that won't be a solution.
Note: I'm currently using H2-Database and Wildfly for my RESTeasy application. But i might change that in future, so the solution should be adaptive.
Best regards,
Maik
Java EE brings everything you need. You can #Schedule a periodically executed cleanup job:
#Singleton
public class Cleanup {
#Schedule(minute = "*/5")
public void clean() {
// will be called every 5 minutes
}
}
Or you programmatically create a Timer which will be executed after a certain amount of time:
#Singleton
public class Cleanup {
#Resource
TimerService timerService;
public void deleteLater(long id) {
String timerInfo = MyEntity.class.getName() + ':' + id;
long timeout = 1000 * 60 * 5; // 5 minutes
timerService.createTimer(timeout, timerInfo);
}
#Timeout
public void handleTimeout(Timer timer) {
Serializable timerInfo = timer.getInfo(); // the information you passed to the timer
}
}
More information can be found in the Timer Service Tutorial.
So I have a Testclass using MSTest and every test works great if I run them one and one, however if I select 2 tests, namely can_register and cannot_Register_existing_username then the second fails (cannot_register_existing_username).
I have let my testclass inherit from an abstract class that looks like this:
public abstract class RollbackCapabilities
{
private TransactionScope _transactionScope;
[TestInitialize]
public virtual void TestInitialize()
{
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
}
[TestCleanup]
public virtual void TestCleanup()
{
Transaction.Current.Rollback();
_transactionScope.Dispose();
}
}
If I comment this file out then it works (but now the data remains in the test-db which I don't want).
With this file above active the second test fails, the tests look like this
[TestMethod]
public void Can_Register()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password= "TestPassword";
model.ConfirmPassword = "TestPassword";
//Act
ActionResult result = ac.Register(model);
//Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
Assert.AreEqual("Home", ((RedirectToRouteResult)result).RouteValues["controller"]);
Assert.AreEqual("Index", ((RedirectToRouteResult)result).RouteValues["action"]);
}
[TestMethod]
public void Cannot_Register_Existing_Username()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password = "TestPassword";
model.ConfirmPassword = "TestPassword";
ac.Register(model);
RegisterModel model2 = new RegisterModel();
model2.UserName = "TestUser";
model2.Password = "OtherTestPassword";
model2.ConfirmPassword = "OtherTestPassword";
//Act
ActionResult result = ac.Register(model2);
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
Assert.AreEqual("", ((ViewResult)result).ViewName);
Assert.AreEqual(model2, ((ViewResult)result).ViewData.Model);
}
and finally the error i get is as follows:
Test method
Viducate.UnitTests.UserHandling.RegisterTests.Cannot_Register_Existing_Username
threw exception: System.Data.EntityCommandExecutionException: An
error occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Users'.
Thats my problem, not big but very annoying and as mentioned if I run the tests one and one it works, it also works but leaves data in the db if I comment out my RollbackCapabilities class
Okay so I found out that my error was that I had created the database (but not tables) by hand because create database is not supported in multi-transaction.
however creating an empty database means that EF assumes there is tables already and that is why it failed with dont know what dbo.users are.
So what I did was created the tables as well and now it works. However this means I can never run this on a new development machine without first creating the tables and database. so annoying.
I think I will set up another test class that does not inherit my abstract rollback class and hade that create the tables permanently... should solve the problem as long as that runs first.
I have created a scheduler class called scheduledInsert. The scheduler Job for this class is registered with following code
public class TestInsertTaskScheduler
{
public static testMethod void testInsertTaskScheduler()
{
scheduledInsert i = new scheduledInsert();
Datetime now = Datetime.now();
System.debug ('Datetime'+now);
String sch = '0 1 * * * ?'; // scheduled to execute every minute
system.schedule('Insert Task S3', sch, i);
System.debug ('After schedule');
}
}
The scheduled class code is
global class scheduledInsert implements Schedulable
{
global void execute(SchedulableContext SC)
{
System.debug('scheduled insert');
}
}
This job (Insert Task S3) does not display under Monitoring scheduled Jobs.
Also the Job does not execute at all.
What's the mistake i am making?
I'm fairly sure it's because you're using a testmethod. When you use a testmethod nothing is committed to the Salesforce database; so, it would make sense that the job doesn't appear in the Scheduled Jobs section. Try removing the testmethod keyword, run it again, and see if it appears.