--- /dev/null
+++ b/tests/account.py
@@ -0,0 +1,83 @@
+import unittest
+from ofxclient import Account
+from ofxclient import BankAccount
+from ofxclient import BrokerageAccount
+from ofxclient import CreditCardAccount
+from ofxclient import Institution
+
+class OfxAccountTests(unittest.TestCase):
+
+    def setUp(self):
+        institution = Institution(
+                id  = '1',
+                org = 'Example',
+                url = 'http://example.com',
+                username = 'username',
+                password = 'password'
+        )
+        self.institution = institution
+
+    def testNumberRequired(self):
+        a = { 'institution': self.institution }
+        self.assertRaises(TypeError,Account,**a)
+
+    def testInstitutionRequired(self):
+        a = { 'number': '12345' }
+        self.assertRaises(TypeError,Account,**a)
+
+    def testMasked(self):
+        account = Account(
+                number = '12345',
+                institution = self.institution
+        )
+        self.assertEqual( account.number_masked(), '***2345' )
+        account.number = '1234'
+        self.assertEqual( account.number_masked(), '***1234' )
+        account.number = '123'
+        self.assertEqual( account.number_masked(), '***123' )
+        account.number = '12'
+        self.assertEqual( account.number_masked(), '***12' )
+        account.number = '1'
+        self.assertEqual( account.number_masked(), '***1' )
+
+    def testDescription(self):
+        account = Account(
+                number = '12345',
+                institution = self.institution
+        )
+        self.assertEqual( account.description, '***2345', 'kwarg is not required and defaults' )
+
+        account = Account(
+                number = '12345',
+                institution = self.institution,
+                description = None
+        )
+        self.assertEqual( account.description, '***2345', 'None defaults' )
+
+        account = Account(
+                number = '12345',
+                institution = self.institution,
+                description = ''
+        )
+        self.assertEqual( account.description, '***2345', 'empty string desc defaults')
+
+        account = Account(
+                number = '12345',
+                institution = self.institution,
+                description = '0'
+        )
+        self.assertEqual( account.description, '0', '0 string is preserved')
+
+        account = Account(
+                number = '12345',
+                institution = self.institution,
+                description = 'passed'
+        )
+        self.assertEqual( account.description, 'passed' )
+
+    def testNoInstitution(self):
+        account = Account(
+                number = '12345',
+                institution = None
+        )
+
--- /dev/null
+++ b/tests/institution.py
@@ -0,0 +1,78 @@
+import unittest
+from ofxclient import Client
+from ofxclient import Institution
+
+class OfxInstitutionTests(unittest.TestCase):
+
+    def testClientDefaultsPreserved(self):
+        i = Institution(
+                id='1',
+                org='org',
+                url='http://example.com',
+                username='username',
+                password='password'
+        )
+
+        c  = Client(institution=i)
+        ic = i.client()
+
+        self.assertEqual( c.id, ic.id )
+        self.assertEqual( c.app_id, ic.app_id )
+        self.assertEqual( c.app_version, ic.app_version )
+        self.assertEqual( c.ofx_version, ic.ofx_version )
+
+    def testClientSomeOverride(self):
+        i = Institution(
+                id='1',
+                org='org',
+                url='http://example.com',
+                username='username',
+                password='password',
+                client_args = {
+                    'app_id': 'capp_id',
+                }
+        )
+
+        c  = Client(institution=i)
+        ic = i.client()
+        self.assertEqual( ic.app_id, 'capp_id', 'overridden app_id')
+        self.assertNotEqual( ic.app_id, c.app_id, 'overridden app_id')
+        self.assertEqual( ic.id, c.id, 'default id')
+        self.assertEqual( ic.app_version, c.app_version, 'default app version')
+        self.assertEqual( ic.ofx_version, c.ofx_version, 'default ofx version')
+
+    def testClientAllOverride(self):
+        i = Institution(
+                id='1',
+                org='org',
+                url='http://example.com',
+                username='username',
+                password='password',
+                client_args = {
+                    'id': 'cid',
+                    'app_id': 'capp_id',
+                    'app_version': 'capp_version',
+                    'ofx_version': 'cofx_version'
+                }
+        )
+
+        c = i.client()
+        self.assertEqual( c.id, 'cid' )
+        self.assertEqual( c.app_id, 'capp_id' )
+        self.assertEqual( c.app_version, 'capp_version' )
+        self.assertEqual( c.ofx_version, 'cofx_version' )
+
+    def testRequiredParams(self):
+        self.assertRaises(TypeError,Institution.__init__)
+
+        a = { 'id': '1' }
+        self.assertRaises(TypeError,Institution,**a)
+
+        a = { 'id': '1', 'org': 'org' }
+        self.assertRaises(TypeError,Institution,**a)
+
+        a = { 'id': '1', 'org': 'org', 'url': 'url' }
+        self.assertRaises(TypeError,Institution,**a)
+
+        a = { 'id': '1', 'org': 'org', 'url': 'url', 'username': 'username' }
+        self.assertRaises(TypeError,Institution,**a)
--- /dev/null
+++ b/tests/ofxconfig.py
@@ -0,0 +1,121 @@
+import unittest
+import tempfile
+import os
+import os.path
+import ofxclient.config
+from ofxclient.config import OfxConfig
+from ofxclient import Institution, CreditCardAccount
+import StringIO
+
+
+
+class OfxConfigTests(unittest.TestCase):
+
+    def setUp(self):
+        self.temp_file = tempfile.NamedTemporaryFile()
+
+    def tearDown(self):
+        self.temp_file.close()
+
+    def testFileCreated(self):
+        file_name = self.temp_file.name
+        self.temp_file.close()
+
+        self.assertFalse(os.path.exists(file_name))
+
+        c = OfxConfig(file_name=file_name)
+        self.assertTrue(os.path.exists(file_name))
+
+        os.remove(file_name)
+
+    def testAddAccount(self):
+        c = OfxConfig(file_name=self.temp_file.name)
+
+        i = Institution(id='1',org='org',url='url',username='user',password='pass')
+        a = CreditCardAccount(institution=i,number='12345')
+
+        c.add_account(a)
+        self.assertEqual( len(c.accounts()), 1 )
+        self.assertEqual( c.account(a.local_id()).local_id(), a.local_id() )
+
+    def testLoadFromFile(self):
+        c = OfxConfig(file_name=self.temp_file.name)
+        i = Institution(id='1',org='org',url='url',username='user',password='pass')
+        a = CreditCardAccount(institution=i,number='12345')
+        c.add_account(a)
+        c.save()
+
+        c = OfxConfig(file_name=self.temp_file.name)
+        got = c.account(a.local_id())
+        self.assertEqual( len(c.accounts()), 1 )
+        self.assertEqual( got.local_id(), a.local_id() )
+        self.assertEqual( got.number, a.number )
+        self.assertEqual( got.institution.local_id(), a.institution.local_id() )
+        self.assertEqual( got.institution.id, a.institution.id )
+        self.assertEqual( got.institution.org, a.institution.org )
+        self.assertEqual( got.institution.url, a.institution.url )
+        self.assertEqual( got.institution.username, a.institution.username )
+        self.assertEqual( got.institution.password, a.institution.password )
+
+    def testFieldsSecured(self):
+        if not ofxclient.config.KEYRING_AVAILABLE:
+            return
+
+        c = OfxConfig(file_name=self.temp_file.name)
+
+        i = Institution(id='1',org='org',url='url',username='user',password='pass')
+        a = CreditCardAccount(institution=i,number='12345')
+        c.add_account(a)
+
+        self.assertTrue( c.parser.is_secure_option(a.local_id(),'institution.username') )
+        self.assertTrue( c.parser.is_secure_option(a.local_id(),'institution.password') )
+
+    def testFieldsRemainUnsecure(self):
+        if not ofxclient.config.KEYRING_AVAILABLE:
+            return
+
+        c = OfxConfig(file_name=self.temp_file.name)
+        i = Institution(id='1',org='org',url='url',username='user',password='pass')
+        a = CreditCardAccount(institution=i,number='12345')
+        c.add_account(a)
+
+        # pretend the user put their password in there in the clear on purpose
+        c.parser.remove_option(a.local_id(),'institution.password')
+        c.parser.set(a.local_id(),'institution.password','pass')
+        c.save()
+
+        c = OfxConfig(file_name=self.temp_file.name)
+        self.assertTrue( c.parser.is_secure_option(a.local_id(),'institution.username') )
+        self.assertFalse( c.parser.is_secure_option(a.local_id(),'institution.password') )
+
+    def testResecuredAfterEncryptAccount(self):
+        if not ofxclient.config.KEYRING_AVAILABLE:
+            return
+
+        c = OfxConfig(file_name=self.temp_file.name)
+        i = Institution(id='1',org='org',url='url',username='user',password='pass')
+        a1 = CreditCardAccount(institution=i,number='12345')
+        c.add_account(a1)
+        a2 = CreditCardAccount(institution=i,number='67890')
+        c.add_account(a2)
+
+        # pretend the user put their password in there in the clear on purpose
+        # to fix something... and then wants it to be resecured later on
+        c.parser.remove_option(a1.local_id(),'institution.password')
+        c.parser.set(a1.local_id(),'institution.password','pass')
+        c.save()
+
+        c = OfxConfig(file_name=self.temp_file.name)
+        self.assertEqual( len(c.accounts()), 2 )
+        self.assertEqual( len(c.encrypted_accounts()), 1 )
+        self.assertEqual( len(c.unencrypted_accounts()), 1 )
+        self.assertTrue( c.parser.is_secure_option(a1.local_id(),'institution.username') )
+        self.assertFalse( c.parser.is_secure_option(a1.local_id(),'institution.password') )
+
+        c.encrypt_account(a1.local_id())
+        self.assertEqual( len(c.accounts()), 2 )
+        self.assertEqual( len(c.encrypted_accounts()), 2 )
+        self.assertEqual( len(c.unencrypted_accounts()), 0 )
+        self.assertTrue( c.parser.is_secure_option(a1.local_id(),'institution.username') )
+        self.assertTrue( c.parser.is_secure_option(a1.local_id(),'institution.password') )
+
--- /dev/null
+++ b/tests/secure_config.py
@@ -0,0 +1,106 @@
+import unittest
+from ofxclient.config import SecurableConfigParser
+from ConfigParser import ConfigParser, NoOptionError
+
+def makeConfig(keyring_available=True,**kwargs):
+    conf = None
+    conf = SecurableConfigParser(keyring_available=keyring_available,**kwargs)
+    conf.add_section('section1')
+    conf.add_section('section2')
+    conf.set('section1','username','USERNAME')
+    conf.set_secure('section1','password','PASSWORD')
+    conf.set('section2','question','answer')
+    conf.set_secure('section2','ssn','111-11-1111')
+    return conf
+
+class IdentifySecureOptionTests(unittest.TestCase):
+
+    def testIsSecureOption(self):
+        c = makeConfig()
+        self.assertTrue(c.is_secure_option('section1','password'))
+        self.assertTrue(c.is_secure_option('section2','ssn'))
+        self.assertFalse(c.is_secure_option('section1','username'))
+        self.assertFalse(c.is_secure_option('section2','question'))
+
+    def testStaysSecure(self):
+        c = makeConfig()
+        self.assertTrue(c.is_secure_option('section1','password'))
+        c.set('section1','password','MYPASS')
+        self.assertTrue(c.is_secure_option('section1','password'))
+
+    def testStaysUnsecure(self):
+        c = makeConfig()
+        self.assertFalse(c.is_secure_option('section1','username'))
+        c.set('section1','username','MYUSER')
+        self.assertFalse(c.is_secure_option('section1','username'))
+
+    def testSetThenSetSecureTurnsSecure(self):
+        c = makeConfig()
+        c.set('section1','foo','bar')
+        self.assertFalse(c.is_secure_option('section1','foo'))
+        c.set_secure('section1','foo','bar')
+        self.assertTrue(c.is_secure_option('section1','foo'))
+        c.set('section1','foo','bar')
+        self.assertTrue(c.is_secure_option('section1','foo'))
+
+    def testItemsHavePasswords(self):
+        c = makeConfig()
+        items = sorted(c.items('section1'))
+        self.assertEqual( items, [ ('password','PASSWORD'), ('username','USERNAME') ] )
+        self.assertEqual( len(items), 2 )
+
+    def testSecureItems(self):
+        c = makeConfig()
+        items = sorted(c.secure_items('section1'))
+        self.assertEqual( items, [ ('password','PASSWORD') ] )
+        self.assertEqual( len(items), 1 )
+        c.remove_option('section1','password')
+        items = sorted(c.secure_items('section1'))
+        self.assertEqual( len(items), 0 )
+
+    def testGet(self):
+        c = makeConfig()
+        self.assertEqual( c.get('section1','password'), 'PASSWORD' )
+        self.assertNotEqual( ConfigParser.get(c,'section1','password'), 'PASSWORD' )
+        self.assertEqual( c.get('section1','username'), 'USERNAME' )
+        c.remove_option('section1','password')
+        self.assertRaises(NoOptionError,c.get,'section1','password')
+
+    def testUnsavedOptions(self):
+        c = makeConfig()
+        s_option = "%s%s" % ('section1','foo2')
+
+        c.set('section1','foo2','bar2')
+        self.assertFalse( s_option in c._unsaved )
+
+        c.remove_option('section1','foo2')
+        self.assertFalse( s_option in c._unsaved )
+
+        c.set_secure('section1','foo2','bar2')
+        self.assertTrue( s_option in c._unsaved )
+        self.assertTrue( c._unsaved[s_option][0] == 'set' )
+        self.assertTrue( c._unsaved[s_option][1] == 'bar2' )
+
+        c.remove_option('section1','foo2')
+        self.assertTrue( s_option in c._unsaved )
+        self.assertTrue( c._unsaved[s_option][0] == 'delete' )
+        self.assertTrue( c._unsaved[s_option][1] == None )
+
+    def testKeyringOffSet(self):
+        c = makeConfig(keyring_available=False)
+        self.assertFalse( c.is_secure_option('section1','username') )
+        self.assertFalse( c.is_secure_option('section1','password') )
+
+        self.assertEqual( c._unsaved, {} )
+
+        c.set_secure('section1','password','PASSWORD')
+        self.assertFalse( c.is_secure_option('section1','password') )
+
+        self.assertEqual( c.get('section1','password'),'PASSWORD' )
+        self.assertEqual( c.get('section1','username'),'USERNAME' )
+
+        c.remove_option('section1','password')
+        self.assertFalse( c.is_secure_option('section1','password') )
+        self.assertEqual( c._unsaved, {} )
+
+    pass
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1 @@
+#
