I'm trying to use NHibernate with SQLite for Unit Testing. But I'm keep getting error
ADOException was unhandled by user code
While preparing INSERT INTO User (First_Name, Last_Name, UserName, Password, Email, Active, Default_Clinic_Identification_Number, Login_Icon, Created_Date, Created_By, Modified_Date, Modified_By) VALUES (#p0, #p1, #p2, #p3, #p4, #p5, #p6, #p7, #p8, #p9, #p10, #p11); select last_insert_rowid() an error occurred
Inner Exception: {"Cannot write to a closed TextWriter."}
I don't know what i'm doing wrong. Here is my code
public class InMemoryDatabaseTest : IDisposable
{
private static Configuration Configuration;
private static ISessionFactory SessionFactory;
protected ISession session;
public InMemoryDatabaseTest()
{
if (Configuration == null)
{
Assembly a = Assembly.Load("Astute.Framework.Data");
Configuration = new Configuration()
.SetProperty(Environment.ReleaseConnections, "on_close")
.SetProperty(Environment.Dialect, typeof(SQLiteDialect).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionDriver, typeof(SQLite20Driver).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionString, "data source=:memory:")
.SetProperty(Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
.AddAssembly(a);
SessionFactory = Configuration.BuildSessionFactory();
}
session = SessionFactory.OpenSession();
new SchemaExport(Configuration).Execute(true, true, false, session.Connection, Console.Out);
}
public void Dispose()
{
session.Dispose();
}
}
[TestClass]
public class Test : InMemoryDatabaseTest
{
[TestMethod]
public void CanSaveUser()
{
object id;
using (var tx = session.BeginTransaction())
{
id = session.Save(new User
{
FirstName = "Imran",
LastName = "Ashraf",
UserName = "imran",
Password = "Test",
Email = "Test#test.com",
IsActive = true,
DefaultClinicIdentifcationNumber = "",
LoginIcon = "",
CreatedBy = 1000000,
CreatedDate = DateTime.Today,
ModifiedBy = 1000000,
ModifiedDate = DateTime.Today
});
tx.Commit();
}
session.Clear();
}
}
I'm getting error on this line id = session.Save. I got this example from http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx
Any idea?
Thanks in advance.
The error message "Inner Exception: {"Cannot write to a closed TextWriter."}" is given when you are trying to write into the Console.Out.
I created a new TextWriter and used it:
TextWriter writer = null;
new SchemaExport(Configuration).Execute(true, true, false, session.Connection, writer);
That fixed that exception.
I can't see the problem. I use this as connection string:
Data Source=:memory:;Version=3;New=True;
You may try it to see if it solves the problem. The New=True; part looks promising.
In my case I noticed that I used two instances of InMemoryDatabaseTest. I deleted one instance from the test.
Related
i'm trying to create an application where data in a list must be inserted into a database table at once. I made some research and found out that this is possible using user-defined table types where in c# a datatable is used and passed to a stored procedure that is executed. now my problem is that there are no data tables in Xamarin.Android. so I thought to use a list instead. my idea was to create a list in the application and pass it to the webservice method, and in my webservice method I receive the list and convert it to a datatable then pass it as a parameter to the stored procedure. I wrote the following codes:
in my webservice:
[WebMethod]
public bool insrt_dt(List<Class1> lst)
{
SqlParameter param;
SqlConnection conn = new SqlConnection(new DBConnection().ConnectionString);
DataTable dt = list_to_dt(lst);
SqlCommand cmd = new SqlCommand("Insert_Customers", conn);
cmd.CommandType = CommandType.StoredProcedure;
if (conn.State == System.Data.ConnectionState.Closed)
{
conn.Open();
}
param = new SqlParameter("#tblcustomers", dt);
param.Direction = ParameterDirection.Input;
param.DbType = DbType.String;
cmd.Parameters.Add(param);
cmd.CommandTimeout = 300;
int a=cmd.ExecuteNonQuery();
if (a > 0)
{
return true;
}
else return false;
}
}
Class1:
public class Class1
{
public int id { get; set; }
public string name { get; set; }
public string country { get; set; }
}
in my Xamarin.Android app
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
Button btn = FindViewById<Button>(Resource.Id.button1);
btn.Click += delegate
{
wr.WebService1 ws = new wr.WebService1();
wr.Class1 class1 = new wr.Class1();
List<wr.Class1> lst = new List<wr.Class1>(){
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
ws.insrt_dt(lst);
ws.insrt_dtCompleted += Ws_insrt_dtCompleted;
};
}
private void Ws_insrt_dtCompleted(object sender, wr.insrt_dtCompletedEventArgs e)
{
bool l = e.Result;
if (l == true)
Toast.MakeText(this, "khh", ToastLength.Long).Show();
else
Toast.MakeText(this, "ijo'pioo", ToastLength.Long).Show();
}
}
but I keep getting this error:
Argument 1: cannot convert from 'System.Collections.Generic.List<app_dt.wr.Class1>' to 'app_dt.wr.Class1[]
so I used these lines instead
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
wr.Class1[] class1s = lst.ToArray();
ws.insrt_dt(class1s);
now I don't get an error, but it doesn't work, I mean why does it say that the webservice method input must be an array and I've created it as a list. any suggestions for this?
As i know, Xamarin do not support System.Data.SqlClient. If you want to use the database for the Xamarin android project, you could use the SQLite.NET.
Install the package from the NuGet.
NuGet: sqlite-net-pcl https://www.nuget.org/packages/sqlite-net-pcl/
For the code sample about how to use the database in Xamarin, you could check the link below. https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows
For Xamarin.Android, you could check the sample code in the link below. https://learn.microsoft.com/en-us/xamarin/android/data-cloud/data-access/using-sqlite-orm
I'm working on an unit test with NUnit for a WebAPI. The Method to test is async and will normally call async a class implementing dapper to access the database. I wanted to fake the data with NSubstitute. this is the API:
public class ModelController : ApiController
{
public async Task<IHttpActionResult> GetAsync()
{
// fake list for testing purposes
List<MyModel> myModels = new List<MyModel>
{
new MyModel
{
ID = 1,
Name = "Test1",
Created = DateTime.Now,
Creator = "Admin"
},
new MyModel
{
ID = 2,
Name = "Test2",
Created = DateTime.Now,
Creator = "Admin"
}
};
return this.Ok(myModels); // <= here would be a call to a class implementing dapper like: return this.Ok(await DbRepo.GetAsync())
}
}
and this is the test:
[TestFixture]
public class ModelControllerTests : ApiController
{
[Test]
public async Task GetAsync_GetAll_ReturnOkHttpResultWithListOfMyModels()
{
private ModelController target = Substitute.For<ModelController>();
List<MyModel> myModels = new List<MyModel>
{
new MyModel
{
ID = 1,
Name = "Test1",
Created = DateTime.Now,
Creator = "Admin"
},
new MyModel
{
ID = 2,
Name = "Test2",
Created = DateTime.Now,
Creator = "Admin"
}
};
OkNegotiatedContentResult<List<MyModel>> result = new OkNegotiatedContentResult<List<MyModel>>(myModels, new ModelController());
(await this.target.GetAsync() as OkNegotiatedContentResult<List<MyModel>>).Returns(result);
OkNegotiatedContentResult<List<MyModel>> actual = (await this.target.GetAsync() as OkNegotiatedContentResult<List<MyModel>>);
Assert.That(actual.Content.Count, Is.GreaterThanOrEqualTo(1)); // <== NullReferenceException because actual is null
}
}
I get a NullReferenceException becaus "actual" is null. But I don't get why. Any ideas?
I'd re-write your test something like this
[TestFixture]
public void GetAsync_GetAll_ReturnOkHttpResultWithListOfMyModels()
{
List<MyModel> expectedModel = new List<MyModel>
{
new MyModel
{
ID = 1,
Name = "Test1",
Created = DateTime.Now,
Creator = "Admin"
},
new MyModel
{
ID = 2,
Name = "Test2",
Created = DateTime.Now,
Creator = "Admin"
}
};
var sut = new ModelController();
var result = sut.GetAsync();
//check you can cast the result first
Assert.That(result.Result, Is.AssignableTo<OkNegotiatedContentResult<IEnumerable<MyModel>>());
var typedResult = (OkNegotiatedContentResult<IList<MyModel>>)result.Result;
//Assert the actual data.
}
Instantiate your ModelController. This is your system under test. You should be using NSubstitute, Moq, FakeItEasy,... to mock/fake out dependencies of your system under test. At this point, you don't have any. You mention Dapper, so you'd want to mock that dependency once you implement it.
You don't need to mark the test method as async either.
Use a hard cast instead of an "as" will result in an exception if it can't cast it which will fail the test. Plus you've already Asserted that this cast should work in the line above.
Also this is just pseudo code it is not guaranteed to run.
apologized to post bit similar question here. i am bit familiar with asp.net mvc but very new in unit testing. do not think that i know lot just see my reputation in stackoverflow.
i like to know how to write unit test code for IsValid and IEnumerable<ModelClientValidationRule> GetClientValidationRules
here i am pasting my code including my model. so anyone help me to write unit test code for the above two function. i am new in unit testing and working with VS2013 and using VS unit testing framework.
my main problem is how to write unit test code for this function specifically IEnumerable<ModelClientValidationRule> GetClientValidationRules
so here is my full code. anyone who often work with unit test then please see and come with code and suggestion if possible. thanks
Model
public class DateValTest
{
[Display(Name = "Start Date")]
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? StartDate { get; set; }
[Display(Name = "End Date")]
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[DateGreaterThanAttribute(otherPropertyName = "StartDate", ErrorMessage = "End date must be greater than start date")]
public DateTime? EndDate { get; set; }
}
custom validation code
public class DateGreaterThanAttribute : ValidationAttribute, IClientValidatable
{
public string otherPropertyName;
public DateGreaterThanAttribute() { }
public DateGreaterThanAttribute(string otherPropertyName, string errorMessage)
: base(errorMessage)
{
this.otherPropertyName = otherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ValidationResult validationResult = ValidationResult.Success;
try
{
// Using reflection we can get a reference to the other date property, in this example the project start date
var containerType = validationContext.ObjectInstance.GetType();
var field = containerType.GetProperty(this.otherPropertyName);
var extensionValue = field.GetValue(validationContext.ObjectInstance, null);
if(extensionValue==null)
{
//validationResult = new ValidationResult("Start Date is empty");
return validationResult;
}
var datatype = extensionValue.GetType();
//var otherPropertyInfo = validationContext.ObjectInstance.GetType().GetProperty(this.otherPropertyName);
if (field == null)
return new ValidationResult(String.Format("Unknown property: {0}.", otherPropertyName));
// Let's check that otherProperty is of type DateTime as we expect it to be
if ((field.PropertyType == typeof(DateTime) || (field.PropertyType.IsGenericType && field.PropertyType == typeof(Nullable<DateTime>))))
{
DateTime toValidate = (DateTime)value;
DateTime referenceProperty = (DateTime)field.GetValue(validationContext.ObjectInstance, null);
// if the end date is lower than the start date, than the validationResult will be set to false and return
// a properly formatted error message
if (toValidate.CompareTo(referenceProperty) < 1)
{
validationResult = new ValidationResult(ErrorMessageString);
}
}
else
{
validationResult = new ValidationResult("An error occurred while validating the property. OtherProperty is not of type DateTime");
}
}
catch (Exception ex)
{
// Do stuff, i.e. log the exception
// Let it go through the upper levels, something bad happened
throw ex;
}
return validationResult;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "isgreater",
};
rule.ValidationParameters.Add("otherproperty", otherPropertyName);
yield return rule;
}
}
What you want to do is test that if the value of EndDate is less than the value of StartDate, then the model is invalid, i.e. that the IsValid() method will throw a ValidationException
// Test that if the end date is less than the start date its invalid
[TestMethod]
[ExpectedException(typeof(ValidationException))]
public void TestEndDateIsInvalidIfLessThanStartDate()
{
// Initialize a model with invalid values
DateValTest model = new DateValTest(){ StartDate = DateTime.Today, EndDate = DateTime.Today.AddDays(-1) };
ValidationContext context = new ValidationContext(model);
DateGreaterThanAttribute attribute = new DateGreaterThanAttribute("StartDate");
attribute.Validate(model.EndDate, context);
}
When you run the test, if will succeed. Conversely if you were to initialize the model using
DateValTest model = new DateValTest(){ StartDate = DateTime.Today, EndDate = DateTime.Today.AddDays(1) };
the test would fail because the model is valid.
I have this controller:
[HttpPost]
public ActionResult Create(Company company)
{
// try to save the record
if (ModelState.IsValid)
{
// create the command
var command = new CreateOrUpdateCompanyCommand
{
CompanyId = company.CompanyId,
Code = company.Code,
Name = company.Name
};
// check for errors
IEnumerable<ValidationResult> errors = _commandBus.Validate(command);
ModelState.AddModelErrors(errors);
if (ModelState.IsValid)
{
var result = _commandBus.Submit(command);
if (result.Success)
return RedirectToAction("Index");
}
}
// if fail
return View("Create", company);
}
I have this test for NUnit:
[Test]
public void Create()
{
const string expectedRouteName = "Index";
// Mock the arguments
var mockRepository = Substitute.For<ICompanyRepository>();
var mockProcessor = Substitute.For<ICommandBus>();
// Arrange
var controller = new CompanyController(mockProcessor, mockRepository);
// Act
var company = new Company
{
Code = "XXXXXXX",
CompanyId = 1,
Name = "Sample company"
};
var result = controller.Create(company) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result, "Should return a ViewResult");
Assert.AreEqual(expectedRouteName, result.RouteValues["action"],
"View name should have been '{0}'", expectedRouteName);
}
This is the Model:
public class Company
{
[Key]
public int CompanyId { get; set; }
[Required(ErrorMessage = "* (xxxx)")]
[MaxLength(7)]
[RegularExpression("^([A-Z0-9]{7})$", ErrorMessage = "xxx")]
[Display(Name = "Code")]
public string Code { get; set; }
[Required(ErrorMessage = "*")]
[MaxLength(40)]
[Display(Name = "Name")]
public string Name { get; set; }
}
When I Run the test, this function always return false: var result = _commandBus.Submit(command); and the test fails.
I don't know how to test it? Should I mock the _commandBus and set it to return true? I tried in this way but unsuccessfully:
var mockCommand = Substitute.For<ICommand>();
mockProcessor.Submit(mockCommand).Success.Returns(true);
To create this project I have got inspiration from this http://efmvc.codeplex.com/
Any advise to me? Thanks.
The command you pass to mockProcessor.Submit(mockCommand).Success.Returns(true) needs to be the same one that the code-under-test passes. As the method news up its own command this will never be the case.
Easiest fix is to match any command when you set up your substitute:
var result = CreateSuccessfulResult(); // <-- fill this in as appropriate
mockProcessor.Submit(null).ReturnsForAnyArgs(result);
Setting the Success field on result inline as per your original test should work too I think, but I find it a bit clearer to specify the result required.
You can improve this a bit by matching the expected command type:
mockProcessor.Submit(Arg.Any<CreateOrUpdateCompanyCommand>()).Returns(result);
You can also inspect the command passed if you'd like to test that:
mockProcessor
.Submit(Arg.Is<CreateOrUpdateCompanyCommand>(x => x.CompanyId = ...))
.Returns(result);
A similar approach can be used to check the Validate call.
There's a bit more info in the NSubstitute docs.
I downloaded Rhino Security today and started going through some of the tests. Several that run perfectly in isolation start getting errors after one that purposely raises an exception runs though. Here is that test:
[Test]
public void EntitiesGroup_IfDuplicateName_Error() {
_authorizationRepository.CreateEntitiesGroup("Admininstrators");
_session.Flush();
var ex = Assert.Throws<GenericADOException>(
() =>
{
_authorizationRepository.CreateEntitiesGroup("Admininstrators");
_session.Flush();
}).InnerException;
Assert.That(ex.Message, Is.StringContaining("unique"));
}
And here are the tests and error messages that fail:
[Test]
public void User_CanSave() {
var ayende = new User {Name = "ayende"};
_session.Save(ayende);
_session.Flush();
_session.Evict(ayende);
var fromDb = _session.Get<User>(ayende.Id);
Assert.That(fromDb, Is.Not.Null);
Assert.That(ayende.Name, Is.EqualTo(fromDb.Name));
}
----> System.Data.SQLite.SQLiteException : Abort due to constraint violation column Name is not unique
[Test]
public void UsersGroup_CanCreate()
{
var group = _authorizationRepository.CreateUsersGroup("Admininstrators");
_session.Flush();
_session.Evict(group);
var fromDb = _session.Get<UsersGroup>(group.Id);
Assert.NotNull(fromDb);
Assert.That(fromDb.Name, Is.EqualTo(group.Name));
}
failed: NHibernate.AssertionFailure : null id in Rhino.Security.Tests.User entry (don't flush the Session after an exception occurs)
Does anyone see how I can reset the state of the in memory SQLite db after the first test?
I changed the code to use nunit instead of xunit so maybe that is part of the problem here as well.
Cheers,
Berryl
This is the base class that instantiates the session
public abstract class DatabaseFixture : IDisposable
{
protected Account _account;
protected IAuthorizationRepository _authorizationRepository;
protected IAuthorizationService _authorizationService;
protected IPermissionsBuilderService _permissionsBuilderService;
protected IPermissionsService _permissionService;
protected User _user;
protected ISession _session;
protected readonly ISessionFactory _factory;
protected DatabaseFixture()
{
BeforeSetup();
SillyContainer.SessionProvider = (() => _session);
var sillyContainer = new SillyContainer();
ServiceLocator.SetLocatorProvider(() => sillyContainer);
Assert.NotNull(typeof(System.Data.SQLite.SQLiteConnection));
var cfg = new Configuration()
.SetProperty(Environment.ConnectionDriver, typeof(SQLite20Driver).AssemblyQualifiedName)
.SetProperty(Environment.Dialect, typeof(SQLiteDialect).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionString, ConnectionString)
.SetProperty(Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
.SetProperty(Environment.ReleaseConnections, "on_close")
.SetProperty(Environment.UseSecondLevelCache, "true")
.SetProperty(Environment.UseQueryCache, "true")
.SetProperty(Environment.CacheProvider,typeof(HashtableCacheProvider).AssemblyQualifiedName)
.AddAssembly(typeof (User).Assembly);
Security.Configure<User>(cfg, SecurityTableStructure.Prefix);
_factory = cfg.BuildSessionFactory();
_session = _factory.OpenSession();
new SchemaExport(cfg).Execute(false, true, false, _session.Connection, null);
_session.BeginTransaction();
SetupEntities();
_session.Flush();
}
protected virtual void BeforeSetup() { }
public virtual string ConnectionString { get { return "Data Source=:memory:"; } }
public void Dispose()
{
if (_session.Transaction.IsActive)
_session.Transaction.Rollback();
_session.Dispose();
}
private void SetupEntities()
{
_user = new User {Name = "Ayende"};
_account = new Account {Name = "south sand"};
_session.Save(_user);
_session.Save(_account);
_authorizationService = ServiceLocator.Current.GetInstance<IAuthorizationService>();
_permissionService = ServiceLocator.Current.GetInstance<IPermissionsService>();
_permissionsBuilderService = ServiceLocator.Current.GetInstance<IPermissionsBuilderService>();
_authorizationRepository = ServiceLocator.Current.GetInstance<IAuthorizationRepository>();
_authorizationRepository.CreateUsersGroup("Administrators");
_authorizationRepository.CreateEntitiesGroup("Important Accounts");
_authorizationRepository.CreateOperation("/Account/Edit");
_authorizationRepository.AssociateUserWith(_user, "Administrators");
_authorizationRepository.AssociateEntityWith(_account, "Important Accounts");
}
}
How are you instantiating the session?
Whenever there's an exception, the session must be discarded. That also means you should almost never share the session between test methods.