I'm trying to use an in-memory SQLite database to test my data layer which is provided by NHibernate.
I've read a load of blogs and articles about getting this setup but I'm now very confused as to why it isn't working.
The problem - when I run a unit test I get the error 'no such table: Student'. The articles I've read suggest this is because the schema isn't getting generated, or, the connection is being closed between my SchemaExport and query. I've checked everywhere I can think of and can't see how either of these scenarios are occuring.
My test output log looks like this:
OPEN CONNECTION
drop table if exists "Student"
drop table if exists "Tutor"
create table "Student" (
ID integer,
Name TEXT,
DoB DATETIME,
TutorId INTEGER,
primary key (ID)
)
create table "Tutor" (
ID integer,
Name TEXT,
primary key (ID)
)
NHibernate: INSERT INTO "Student" (Name, DoB, TutorId) VALUES (#p0, #p1, #p2); select last_insert_rowid();#p0 = 'Text1', #p1 = 01/12/2010 14:55:05, #p2 = NULL
14:55:05,750 ERROR [TestRunnerThread] AbstractBatcher [(null)]- Could not execute query: INSERT INTO "Student" (Name, DoB, TutorId) VALUES (#p0, #p1, #p2); select last_insert_rowid()
System.Data.SQLite.SQLiteException (0x80004005): SQLite error
no such table: Student
at System.Data.SQLite.SQLite3.Prepare(String strSql, SQLiteStatement previous, String& strRemain)
at System.Data.SQLite.SQLiteCommand.BuildNextCommand()
at System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
14:55:05,781 ERROR [TestRunnerThread] ADOExceptionReporter [(null)]- SQLite error
no such table: Student
DISPOSE
CLOSING CONNECTION
Originally I was using my own code for the connection/session management but have moved to the code in this blog post translated to C# and with a couple changes to the DBConfig method and some debug statements to show the state of the connection.
private FluentNHibernate.Cfg.Db.IPersistenceConfigurer GetDBConfig()
{
return SQLiteConfiguration.Standard
.ConnectionString((ConnectionStringBuilder cs) => cs.Is(CONNECTION_STRING))
.ProxyFactoryFactory("NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu")
.Raw("connection.release_mode", "on_close");
}
I added the on_close after reading this
My test code looks like this:
[Test]
public void CanGetStudentById()
{
using (var scope = new SQLiteDatabaseScope<StudentMapping>())
{
using (ISession sess = scope.OpenSession())
{
// Arrange
var repo = new StudentRepository();
repo.Save(new Student() { Name = "Text1", DoB = DateTime.Now });
// Act
var student = repo.GetById(1);
// Assert
Assert.IsNotNull(student);
Assert.AreEqual("Text1", student.Name);
}
}
}
What have I overlooked here?
Update: I created a copy of the class that connects to an SQLite file DB and it worked fine. So it has to be something to do with the connection being closed.
If you change your test method to the following, does it work?
[Test]
public void CanGetStudentById()
{
using (var scope = new SQLiteDatabaseScope<StudentMapping>())
{
using (ISession sess = scope.OpenSession())
{
// Arrange
sess.Save(new Student() { Name = "Text1", DoB = DateTime.Now });
// Act
var student = sess.Get<Student>(1);
// Assert
Assert.IsNotNull(student);
Assert.AreEqual("Text1", student.Name);
}
}
}
I would hazard to guess that your StudentRepository is opening its own session and hence doesn't see the table.
Related
I made an Apex Class in the Sandbox to call a List.
Now I need to implement it in the production. To do so, I need to implement a Test with at least 75% Success.
The Apex Class produces a List of “dfind_Research_Projekt__c” from which “dfind_Potenzieller_Kandidat__c “ is the actual record, I use this list to make an iteration and show all the “dfind_Research_Projekt__c” on the page from “dfind_Potenzieller_Kandidat__c “.
This is my Apex Class:
public with sharing class dfind_Pot_Job_Application_List {
#AuraEnabled
//Get Pot Job Application List
public static List<dfind_Research_Projekt__c> getJobApp(Id recordId) {
List<dfind_Research_Projekt__c> JobAppList = [Select Id, Name, dfind_Potenzieller_Kandidat__c, dfind_Job__c,
LastModifiedById, dfind_Bewerbungsdatum__c, dfind_Job_Name__c,
OwnerId
from dfind_Research_Projekt__c
where dfind_Potenzieller_Kandidat__c = :recordId
ORDER BY dfind_Bewerbungsdatum__c DESC NULLS LAST];
return JobAppList;
}
//Get User
#AuraEnabled
public static user fetchUser(){
User u = [select id,Name from User where id =: userInfo.getUserId()];
return u;
}
}
This is my test:
#isTest
public class TESTdfind_pot_job_app {
static testMethod void myUnitTest() {
//Create Data for Customer Objet
cxsrec__Potential_candidate__c objKandi = new cxsrec__Potential_candidate__c();
objKandi.Name = 'Test Kandidat';
insert objKandi;
//Create List
List<dfind_Research_Projekt__c> listOfPotApp = new List<dfind_Research_Projekt__c>{
new dfind_Research_Projekt__c(Name='Test Appplication'
, dfind_Job__c='a0w0X000008KKB5QAO'
, dfind_Potenzieller_Kandidat__c = objKandi.Id
, dfind_Bewerbungsdatum__c = Datetime.now()
, OwnerId= '0050X000007vz5MQAQ'),
new dfind_Research_Projekt__c(Name='Test Appplication 1'
, dfind_Job__c='a0w1x0000013aSRAAY'
, dfind_Potenzieller_Kandidat__c = objKandi.Id
, dfind_Bewerbungsdatum__c = Datetime.now()
, OwnerId= '0050X000007vz5MQAQ'),
new dfind_Research_Projekt__c(Name='Test Appplication 2'
, dfind_Job__c='a0w1x000000JJSBAA4'
, dfind_Potenzieller_Kandidat__c = objKandi.Id
, dfind_Bewerbungsdatum__c = Datetime.now()
, OwnerId= '0050X000007vz5MQAQ')
};
insert(listOfPotApp);
Test.startTest();
// Starts the scope of test
// Now check if it is giving desired results using system.assert
// Statement.New invoice should be created
List<dfind_Research_Projekt__c> JobAppList = new List<dfind_Research_Projekt__c>(listOfPotApp);
Test.stopTest(); // Ends the scope of test
for(Integer i=0;i<JobAppList.Size();i++) {
system.assertEquals(JobAppList[i].dfind_Potenzieller_Kandidat__c,objKandi.Id);
System.debug(i + 'Kandidat: ' + JobAppList[i].dfind_Potenzieller_Kandidat__c + ';');
System.debug(i + ': ' + objKandi.Id + ';');
}
system.assertEquals(1,1);
}
}
The hard-coded Ids in your unit test won't work. Your unit tests executes in an isolated data context and must generate all of its own test data.
As written, this test doesn't really do anything. It does not invoke the code you intend to test, as it must to evaluate its behavior and obtain code coverage. You'd need to call fetchUser() and getJobApp() at some point and write assertions about their return values. The assertions that are currently present are all tautological; they're guaranteed to pass and provide no information.
See How do I write an Apex unit test? on Salesforce Stack Exchange for introductory resources.
I'm trying to create an initial DB state in DB Unit like this...
public function getDataSet() {
$primary = new \PHPUnit\DbUnit\DataSet\CompositeDataSet();
$fixturePaths = [
"test/Seeds/Upc/DB/UpcSelect.xml",
"test/Seeds/Generic/DB/ProductUpcSelect.xml"
];
foreach($fixturePaths as $fixturePath) {
$dataSet = $this->createXmlDataSet($fixturePath);
$primary->addDataSet($dataSet);
}
return $primary;
}
Then after my query I'm attempting to call this user-defined function...
protected function compareDatabase(String $seedPath, String $table) {
$expected = $this->createFlatXmlDataSet($seedPath)->getTable($table);
$result = $this->getConnection()->createQueryTable($table, "SELECT * FROM $table");
$this->assertTablesEqual($expected, $result);
}
The idea here is that I have an initial DB state, run my query, then compare the actual table state with the XML data set representing what I expect the table to look like. This process is described in PHPUnit's documentation for DBUnit but I keep having an exception thrown...
PHPUnit\DbUnit\InvalidArgumentException: There is already a table named upc with different table definition
Test example...
public function testDeleteByUpc() {
$mapper = new UpcMapper($this->getPdo());
$mapper->deleteByUpc("someUpcCode1");
$this->compareDatabase("test/Seeds/Upc/DB/UpcAfterDelete.xml", 'upc');
}
I seem to be following the docs...how is this supposed to be done?
This was actually unrelated to creating a second XML Dataset. This exception was thrown because the two fixtures I loaded in my getDataSet() method both had table definitions for upc.
I am using In-Memory database (using ServiceStack.OrmLite.Sqlite.Windows) for unit testing in servicestack based web api. I want to test the service endpoints which depends on stored Procedures through In-Memory database for which i have gone through the link Servicestack Ormlite SqlServerProviderTests, the unit test class that i am using for the test is as follows,
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using NUnit.Framework;
using ServiceStack.Text;
using ServiceStack.Configuration;
using ServiceStack.Data;
namespace ServiceStack.OrmLite.Tests
{
public class DummyTable
{
public int Id { get; set; }
public string Name { get; set; }
}
[TestFixture]
public class SqlServerProviderTests
{
private IDbConnection db;
protected readonly ServiceStackHost appHost;
public SqlServerProviderTests()
{
appHost = TestHelper.SetUp(appHost).Init();
db = appHost.Container.Resolve<IDbConnectionFactory>().OpenDbConnection("inventoryDb");
if (bool.Parse(System.Configuration.ConfigurationManager.AppSettings["IsMock"]))
TestHelper.CreateInMemoryDB(appHost);
}
[TestFixtureTearDown]
public void TearDown()
{
db.Dispose();
}
[Test]
public void Can_SqlColumn_StoredProc_returning_Column()
{
var sql = #"CREATE PROCEDURE dbo.DummyColumn
#Times integer
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #Temp
(
Id integer NOT NULL,
);
declare #i int
set #i=1
WHILE #i < #Times
BEGIN
INSERT INTO #Temp (Id) VALUES (#i)
SET #i = #i + 1
END
SELECT * FROM #Temp;
DROP TABLE #Temp;
END;";
db.ExecuteSql("IF OBJECT_ID('DummyColumn') IS NOT NULL DROP PROC DummyColumn");
db.ExecuteSql(sql);
var expected = 0;
10.Times(i => expected += i);
var results = db.SqlColumn<int>("EXEC DummyColumn #Times", new { Times = 10 });
results.PrintDump();
Assert.That(results.Sum(), Is.EqualTo(expected));
results = db.SqlColumn<int>("EXEC DummyColumn 10");
Assert.That(results.Sum(), Is.EqualTo(expected));
results = db.SqlColumn<int>("EXEC DummyColumn #Times", new Dictionary<string, object> { { "Times", 10 } });
Assert.That(results.Sum(), Is.EqualTo(expected));
}
}
}
when i tried to execute this through Live-DB, it was working fine. but when i tried for In-Memory DB was getting Exceptions as follows,
System.Data.SQLite.SQLiteException : SQL logic error or missing database near "IF": syntax error
near the code line,
db.ExecuteSql("IF OBJECT_ID('DummyColumn') IS NOT NULL DROP PROC DummyColumn");
i commented the above line and executed the test case but still i am getting exception as follows,
System.Data.SQLite.SQLiteException : SQL logic error or missing database near "IF": syntax error
for the code line,
db.ExecuteSql(sql);
the In-Memory DB Created is as follows, and its working fine for remaining cases.
public static void CreateInMemoryDB(ServiceStackHost appHost)
{
using (var db = appHost.Container.Resolve<IDbConnectionFactory>().OpenDbConnection("ConnectionString"))
{
db.DropAndCreateTable<DummyData>();
TestDataReader<TableList>("Reservation.json", "InMemoryInput").Reservation.ForEach(x => db.Insert(x));
db.DropAndCreateTable<DummyTable>();
}
}
why we are facing this exception is there any other way to add and run stored Procedure in In-Memory DB with Sqlite??
The error is because you're trying to run SQL Server-specific queries with TSQL against an in memory version of Sqlite - i.e. a completely different, embeddable database. As the name suggests SqlServerProviderTests only works on SQL Server, I'm confused why you would try to run this against Sqlite?
SQLite doesn't support Stored Procedures, TSQL, etc so trying to execute SQL Server TSQL statements will always result in an error. The only thing you can do is fake it with a custom Exec Filter, where you can catch the exception and return whatever custom result you like, e.g:
public class MockStoredProcExecFilter : OrmLiteExecFilter
{
public override T Exec<T>(IDbConnection dbConn, Func<IDbCommand, T> filter)
{
try
{
return base.Exec(dbConn, filter);
}
catch (Exception ex)
{
if (dbConn.GetLastSql() == "exec sp_name #firstName, #age")
return (T)(object)new Person { FirstName = "Mocked" };
throw;
}
}
}
OrmLiteConfig.ExecFilter = new MockStoredProcExecFilter();
I am trying to create a Salesforce unit test for a new trigger I created.
trigger SOSCreateCaseCustom on SOSSession (before insert) {
List<Event> aplist = new List<Event>();
List<SOSSession> sosSess = Trigger.new;
for (SOSSession s : sosSess) {
try {
Case caseToAdd = new Case();
caseToAdd.Subject = 'SOS Video Chat';
if (s.ContactId != null) {
caseToAdd.ContactId = s.ContactId;
} else {
List<Contact> contactInfo = [SELECT Id from Contact WHERE Email = :s.AppVersion];
if (!contactInfo.isEmpty()) {
caseToAdd.ContactId = contactInfo[0].Id;
s.ContactId = contactInfo[0].Id;
}
}
insert caseToAdd; s.CaseId = caseToAdd.Id;
}catch(Exception e){}
}
}
Here is my unit test:
#isTest
private class SOSCreateCaseCustomTest {
static testMethod void validateSOSCreateCase() {
String caseSubject = 'SOS Video Chat';
// set up case to add
SOSSession s = new SOSSession();
insert s;
Case caseToAdd = new Case(Subject='SOS Video Chat');
caseToAdd.ContactId = s.ContactId;
insert caseToAdd;
Case ca = [SELECT Subject, ContactId from Case where Subject =: caseSubject];
// Test that escaltion trigger correctly escalate the question to a case
System.assertEquals(s.ContactId, ca.ContactId);
}
}
I keep getting this error.
System.QueryException: List has more than 1 row for assignment to SObject
I am new to Apex and I have no idea how to fix this. Any Salesforce and Apex experts out there who can help? Thanks!
I think this one:
Case ca = [SELECT Subject, ContactId from Case where Subject =: caseSubject];
Because the casSubject may query more then one Case.... You should use List
The following line is causing issue :
Case ca = [SELECT Subject, ContactId from Case where Subject =: caseSubject];
It is returning two cases, the one you inserted in test data and other that is inserted by trigger. So it is having two records for Subject 'SOS Video Chat';
If you change the Subject from 'SOS Video Chat' to any other String it will run successfully.
I am trying to update a record in one of my Azure Mobile tables using the “update” function in the azure mobile C++ header. But I get an exception. Below is what my code looks like:
void DBUtils::DBQuestion::UpdateQuestionInTable(std::shared_ptr<azure::mobile::table> table)
{
auto obj = json::value::object();
obj[U("id")] = json::value::string(ID);
obj[U("QuestionText")] = json::value::string(QuestionText);
obj[U("AnswerLatitude")] = json::value::number(AnswerLatitude);
obj[U("AnswerLongitude")] = json::value::number(AnswerLongitude);
table->update(obj);
}
I have verified that the ID above is a valid one actually present in the table. A similar insert operation (which doesn’t specify the ID field) actually succeeds:
void DBUtils::DBQuestion::InsertIntoTable(std::shared_ptr<azure::mobile::table> table)
{
auto obj = json::value::object();
obj[U("QuestionText")] = json::value::string(QuestionText);
obj[U("AnswerLatitude")] = json::value::number(AnswerLatitude);
obj[U("AnswerLongitude")] = json::value::number(AnswerLongitude);
table->insert(obj);
}
What am I doing wrong?
Azure Mobile recently updated its table schema so that the Id field is now a string, which gets filled in by the server with a Guid value if the client doesn’t set it.
This change has introduced a bug in the C++ library. As a workaround, you can try calling the other overload for update, the one that takes the ID string and the object.
void DBUtils::DBQuestion::UpdateQuestionInTable(utility::string_t id, std::shared_ptr<azure::mobile::table> table)
{
auto obj = json::value::object();
obj[U("QuestionText")] = json::value::string(QuestionText);
obj[U("AnswerLatitude")] = json::value::number(AnswerLatitude);
obj[U("AnswerLongitude")] = json::value::number(AnswerLongitude);
ID = id;
table->update(ID, obj);
}