Data access, unit testing, dependency injection

后端 未结 3 1238
伪装坚强ぢ
伪装坚强ぢ 2020-12-21 04:29

I\'ve recently got a task to create a simple utility that allows to import data from a file with special format to the database. I\'ve implemented console application with f

相关标签:
3条回答
  • 2020-12-21 05:02

    Here is a simple solution: Instead of calling you data access class directly, use helper methods:

      public void insert (...) {
          DataAccess.insert (...);
      }
    

    Now you can override these calls. I suggest to split the tests like so:

    1. Create a couple of tests which make sure that DataAccess does the right thing when it gets the right parameters.

    2. In the mockup tests, simply collect the parameters sent to insert(). Don't call DataAccess at all.

    The tests in #1 will make sure that writing the data into the DB will work while the tests in #2 will make sure that you call DataAccess with the correct values. The latter tests will run very quickly, which will make it easy to test special cases, etc.

    You don't need to run the tests from #1 all the time, either. Only when you change something in DataAccess or before a release. This will make testing efficient and pleasant.

    0 讨论(0)
  • 2020-12-21 05:05

    I need to create an interface and implement it in the data access class. Also I will have to add a constructor to the business logic class that will accept parameter of that interface type. So this means that I will end up creating data access class in the application Main() method and something tells me this not the best approach (is it really ok that the entry point should know about some data access things? what if the chain is much longer or there should be several chains?)

    On the contrary! This is the best approach, at least from a testability perspective.

    The only way to make your business logic layer testable is to isolate it from your data access layer by doing exactly what you're contemplating.

    Your top-level application is where the buck stops - it's the only component that should need to know what the concrete data access class is.

    If the chain is much longer or there are several chains, that's no big deal (though you may want to consider collapsing some application layers if it gets out of hand). Consider this potential code in a Model-View-Presenter app's View, where the Presenter has a dependency on a CustomerService, which has a dependency on a Repository and a dependency on an AccountingService (which is also dependent on the Repository):

    public CustomerView() {
        IRespository       repository        = new ConcreteRepository();
        IAccountingService accountingService = new ConcreteAccountingService(repository);
        ICustomerService   customerService   = new ConcreteCustomerService(accountingService, repository)
        this._Presenter = new CustomerPresenter(customerService);
    }
    

    Finally, there's no need to use a dependency injection container if you don't want to (though some of them are surprisingly lightweight) - dependency injection by hand works fine until you start repeating yourself all over the place (or find you want to configure the dependencies at runtime).

    0 讨论(0)
  • 2020-12-21 05:09

    Assuming that you are using LINQ to SQL, maybe you could use the repository pattern to wrap the DataContext into an interface that you can later mock, thus making unit testing possible.

    There are some articles about this subject around the internet, here is one: http://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx

    0 讨论(0)
提交回复
热议问题