(This is similar to this question: How to set up separate test and development database in meteor, however it's 2 years old and meteor has changed a lot since then.)
I'm trying to create my own package and I want to run unit tests. I want to ensure that my queries are correct, so I want to actually run queries against a test database instead of just stubbing the functions.
I have two questions:
How can I tell Meteor to run against a test database instead of my real one?
What's the best way to easily populate that test database with data?
Ideally, I'd a setup step to clear than populate the test database, so I always know exactly what data is in each.
I'm a Tinytest novice (though I've used other unit test frameworks), so code samples are much appreciated.
Here's an example similar to what we use:
var resetCollection = function(name) {
var Collection = this[name];
if (Collection)
// if the collection is already defined, remove its documents
Collection.remove({});
else
// define a new unmanaged collection
this[name] = new Mongo.Collection(null);
};
reset = function() {
var collections = ['Comments', 'Posts'];
// reset all of the collections
_.each(collections(function(name) {resetCollection(name);}));
// insert some documents
var postId = Posts.insert({title: 'example post'});
Comments.insert({postId: postId, message: 'example comment'});
};
Tinytest.add('something', function(test) {
reset();
var post = Posts.findOne();
var comment = Comments.findOne();
return test.equal(comment.postId, post._id);
});
At the start of each test we call reset which cleans up the database and creates the necessary collections.
How can I tell Meteor to run against a test database instead of my real one?
When you test your packages, a separate database will be created for you. There is no need to manually specify your db path.
What's the best way to easily populate that test database with data?
The example above should give you some pointers. I've found the best way to avoid conflicts between packages is to use unmanaged collections in tests (name = null). The resetCollection function should correctly avoid redefining any managed collections which are exported by other packages. Also see this question for more details.
Related
For purpose of demonstration assume that I have the following schema + model:
const UserSchema = mongoose.Schema({
userName: {
type: String,
required: true,
unique: true
}
});
const UserModel = mongoose.model("User", UserSchema);
I intend to have a large schema, so for easier maintenance I have it defined in user.schema.js, whereas the corresponding user model is in a separate file.
I covered the model with unit tests and began contemplating doing the same for the schema module, except... I am not sure if there is a point?
I have seen people test their models/schemas using an actual test database connection, but that is not a unit test IMO, it resembles an integration test more, and that is a different concept. For a unit test of a schema only I don't care if MongoDB itself works correctly.
The Internet (including SO) has also revealed code, which tests Mongoose's validation. This is closer to what I wanted to do as the basic idea is to check whether all expected props and restrictions are in the schema. It would look like this:
it('should be invalid if username is empty', function(done) {
new UserModel().validate(function(err) {
expect(err.errors.name).to.exist;
done();
});
});
If testing with a live DB one could change .validate to .save too.
Then it dawned upon me that I would be doing two things here:
Testing the behaviour of Mongoose, which I also don't care/intend/want to do.
Essentially duplicating my schema. If I later decide to change anything in it, I would have to change the unit test too.
This seems like unit testing a configuration object, and that is pointless, aside from maybe making sure that I wrote my regexes correctly and stuff like that.
Questions
I have thus decided not to test the schema at all. Does that make sense or am I missing something?
As a side question, do you believe there is a point in writing tests with a DB connection? This would test my schema + mongoose + mongo and somehow I find it redundant.
In documentation it shows how to use server global to create models and everything, but it is possible to use scenarios to populate the mock database? Or are we supposed to create objects on the fly?
The "default scenario" is really meant to be a place to seed the database during development, as each test is really its own scenario.
If you wanted to share some common seed logic across all tests, you could export a function and share that, calling it either in beforeEach within a test module, or even the moduleForAcceptance helper so it runs every time.
You might even be able to make a new file under /scenarios just to keep things organized (I'm not 100% on this due to the way modules are read in). It doesn't really matter where you put it, though.
Untested, but something like the following:
// mirage/scenarios/tests.js
export default function(server) {
// generic test setup
}
// tests/helpers/module-for-acceptance.js
import 'testSetup' from 'mirage/scenarios/tests';
...
testSetup(server)
I'm using MSTest to retrofit unit testing in our application. A number of our tests will use a mocked list of objects (classes) that would normally come from our database. I'd like to save this list in the test project and then read the list, as necessary, for each test that needs it. Is there a best practice for doing this? BTW, these lists could contains hundreds or thousands of items.
For such cases, I would use data driven tests.
Look at the example at msdn site http://msdn.microsoft.com/en-us/library/ms182527.aspx
There are two solutions at least
Deserialize JSON to domain objects
Using library Json.Net you could deserialize text file contains JSON into hierarhy of objects
var hierarchy = JsonConvert.DeserializeObject<Root>(testJson)
See complete example here
Benefits
Easy to edit
Complex hierarhy supported
Test data could be stored in separate text files
Drawbacks
Could be quite complex to track changes at domain object with time
No schema supported
NDbUnit is a .NET library for managing database state during testing
In case if you involved ORM during your tests, you could load data using NdbUnit to SQLite from XML file that created according to database XSD
SQLiteConnection connection = boundSession.GetConnection();
using (var cmd = new SQLiteCommand("PRAGMA foreign_keys = OFF", connection))
{
cmd.ExecuteNonQuery();
}
var sqlLiteUnitTest = new SqlLiteDbUnitTest(connection);
sqlLiteUnitTest.ReadXmlSchema(xsdFile);
sqlLiteUnitTest.ReadXml(xmlDataFile);
sqlLiteUnitTest.PerformDbOperation(DbOperationFlag.CleanInsertIdentity);
using (var cmd = new SQLiteCommand("PRAGMA foreign_keys = ON", (SQLiteConnection)connection))
{
cmd.ExecuteNonQuery();
}
See complete example here
Benefits
Much easy to handle a lot of data, because of XSD
Suitable for complex integration test suites and supports differents SQL engines
Drawbacks
This is integration testing, not unittesting
XSD usually contains only objects from database
You need to keep XSD up to date, and be able to regenerate XML in case of XSD changes
I'm trying to write a suite of integration tests, where I have custom code which uses the Umbraco API. The Umbraco database lives in a SQL Server CE 4.0 database (*.sdf file) and I've managed to get that association working fine.
My problem looks to be dependancies in the Umbraco code. For example, I would like to create a new user for my tests, so I try:
var user = User.MakeNew("developer", "developer", "mypassword", "my.email#email.com", adminUserType);
Now as you can see, I have pass a user type which is an object. I've tried two separate ways to create the user type, both of which fail due to a null object exception:
var adminUserType = UserType.GetUserType(1);
var adminUserType2 = new UserType(1);
The problem is that in each case the UserType code calls it's Cache method which uses the HttpRuntime class, which naturally is null.
My question is this: Can someone suggest a way of writing integration tests against Umbraco code? Will I have to end up using a mocking framework such as TypeMock or JustMock?
Here are some resources that may help:
http://www.aaron-powell.com/unit-testing-with-umbraco
http://stream.umbraco.org/video/726639/aaron-powell-unit-testing
I'm trying to write unit tests for parts of my Node app. I'm using Mongoose for my ORM.
I've searched a bunch for how to do testing with Mongoose and Node but not come with anything. The solutions/frameworks all seem to be full-stack or make no mention of mocking stuff.
Is there a way I can mock my Mongoose DB so I can return static data in my tests? I'd rather not have to set up a test DB and fill it with data for every unit test.
Has anyone else encountered this?
I too went looking for answers, and ended up here. This is what I did:
I started off using mockery to mock out the module that my models were in. An then creating my own mock module with each model hanging off it as a property. These properties wrapped the real models (so that child properties exist for the code under test). And then I override the methods I want to manipulate for the test like save. This had the advantage of mockery being able to undo the mocking.
but...
I don't really care enough about undoing the mocking to write wrapper properties for every model. So now I just require my module and override the functions I want to manipulate. I will probably run tests in separate processes if it becomes an issue.
In the arrange part of my tests:
// mock out database saves
var db = require("../../schema");
db.Model1.prototype.save = function(callback) {
console.log("in the mock");
callback();
};
db.Model2.prototype.save = function(callback) {
console.log("in the mock");
callback("mock staged an error for testing purposes");
};
I solved this by structuring my code a little. I'm keeping all my mongoose-related stuff in separate classes with APIs like "save", "find", "delete" and no other class does direct access to the database. Then I simply mock those in tests that rely on data.
I did something similar with the actual objects that are returned. For every model I have in mongoose, I have a corresponding class that wraps it and provides access-methods to fields. Those are also easily mocked.
Also worth mentioning:
mockgoose - In-memory DB that mocks Mongoose, for testing purposes.
monckoose - Similar, but takes a different approach (Implements a fake driver). Monckoose seems to be unpublished as of March 2015.