I begin studying Unit testing with "(NUnit)". I know that this type of testing is used to test "classes" , "functions" and the "interaction between those functions".
In my case I develop "asp.net web applications".
How can i use this testing to test my
pages(as it is considered as a class
and the methods used in)and in which sequence?, i have three layers:
Interface layer(the .cs of each page).
Data access layer(class for each entity)(DAL).
Database layer (which contains connection to the database,open connection,close connection,....etc).
Business layer(sometimes to make calculation or some separate logic).
How to test the methods that make connection to the database?
How to make sure that my testing not a waste of time?.
There are unit and integration tests. Unit testing is testing single components/classes/methods/functions and interaction between them but with only one real object (system under test-SUT) and test doubles. Test doubles can be divided to stubs and mocks. Stubs provide prepared test data to SUT. That way you isolate SUT from the environment. So You don't have to hit database, web or wcf services and so on and you have same input data every time. Mocks are used to verify that SUT works as expected. SUT calls methods on mock object not even knowing it is not real object. Then You verify that SUT works by asserting on mock object. You can write stubs and mocks by hand or use one of many mocking frameworks. One of which is http://code.google.com/p/moq/
If You want to test interaction w/database that's integration testing and generally is a lot harder. For integration testing You have to setup external resources in well known state.
Let's take your layers:
You won't be able to unit test it. Page is to tightly coupled to ASP.NET runtime. You should try to not have much code in code behind. Just call some objects from your code behind and test those objects. You can look at MVC design patters. If You must test Your page You should look at http://watin.org/. It automates Your internet browser, clicks buttons on page and verifies that page displays expected result's.
This is integration testing. You put data in database, then read it back and compare results. After test or before test You have to bring test database to well known state so that tests are repeatable. My advice is to setup database before test runs rather then after test runs. That way You will be able to check what's in database after test fails.
I don't really know how that differs from that in point no. 2.
And this is unit testing. Create object in test, call it's methods and verify results.
How to test methods that make connections to the database is addresed in point 2.
How to not waste time? That will come with experience. I don't have general advice other then don't test properties that don't have any logic in it.
For great info about unit testing look here:
http://artofunittesting.com/
http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627/ref=sr_1_2?ie=UTF8&s=books&qid=1306787051&sr=1-2
http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054/ref=sr_1_1?ie=UTF8&s=books&qid=1306787051&sr=1-1
Edit:
SUT, CUT - System or Class under test. That's what You test.
Test doubles - comes from stunt doubles. They do dangerous scenes in movies so that real actors don't have to. Same here. Test doubles replace real objects in tests so that You can isolate SUT/CUT in tests from environment.
Let's look at this class
public class NotTestableParty
{
public bool ShouldStartPreparing()
{
if (DateTime.Now.Date == new DateTime(2011, 12, 31))
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
How will You test that this class does what it should on New Years Eve? You have to do it on New Years Eve :)
Now look at modified Party class
Example of stub:
public class Party
{
private IClock clock;
public Party(IClock clock)
{
this.clock = clock;
}
public bool ShouldStartPreparing()
{
if (clock.IsNewYearsEve())
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
public interface IClock
{
bool IsNewYearsEve();
}
public class AlwaysNewYearsEveClock : IClock
{
public bool IsNewYearsEve()
{
return true;
}
}
Now in test You can pass the fake clock to Party class
var party = new Party(new AlwaysNewYearsEveClock());
Assert.That(party.ShouldStartPreparing(), Is.True);
And now You know if Your Party class works on New Years Eve. AlwaysNewYearsEveClock is a stub.
Now look at this class:
public class UntestableCalculator
{
private Logger log = new Logger();
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public class Logger
{
public void Log(string message)
{
// .. do some logging
}
}
How will You test that Your class logs message. Depending on where You log it You have to check the file or database or some other place. That wouldn't be unit test but integration test. In order to unit test You do this.
public class TestableCalculator
{
private ILogger log;
public TestableCalculator(ILogger logger)
{
log = logger;
}
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public interface ILogger
{
void Log(string message);
}
public class FakeLogger : ILogger
{
public string LastLoggedMessage;
public void Log(string message)
{
LastLoggedMessage = message;
}
}
And in test You can
var logger = new FakeLogger();
var calculator = new TestableCalculator(logger);
try
{
calculator.Divide(10, 0);
}
catch (DivideByZeroException ex)
{
Assert.That(logger.LastLoggedMessage, Is.EqualTo("Don't divide by 0"));
}
Here You assert on fake logger. Fake logger is mock object.
Related
I know that unit tests should run isolated and should never depend on other unit tests.
However, I also write some integration tests with MSTest and sometimes they produce a result that I would like to reuse in another test.
For example:
Creating a user
Searching this user from the database
Deleting the user
Each of those points would be an integration test for me, so I would like to write methods that look like this:
User _myNewUser;
[TestMethod]
public void CreateAUserTest()
{
//User gets created here somehow....
_myNewUser = successfullyCreatedUser;
}
And this test should run after the preceeding test:
User _myNewUser;
[TestMethod]
public void SearchingUserTest()
{
var user = searchUser(_newUser.GetName());
//Assert that user is not null
}
You can see that I use the value of the first test in the second test.
With a playlist I could make sure that both tests run in the correct order.
However, in VS 2022 each test gets executed in isolation, so what I am trying to do does not work.
_newUser is always null if I run the second test, even if the first test was a success.
Is my idea bad in general?
If not: How can I use the produced data of a test in another test?
I usually extract the contents of a test like that into a separate staging function that does not contain the [TestMethod] attribute, so that I can reuse it to stage other tests.
private void Stage_CreateAUser()
{
//do work from CreateAUserTest()
}
[TestMethod]
public void CreateAUserTest()
{
Stage_CreateAUser();
}
private void Stage_SearchingUser()
{
//do work from CreateAUserTest()
}
[TestMethod]
public void SearchingUserTest()
{
Stage_CreateAUser();
Stage_SearchingUser();
}
Etc...
New to WebFlux, reactive, and handlers.
I am able to get a Mono<> from a ServerRequest and process the contained POJO to add a new tuple to a database. But, it seems like there should be a "better" or "more accepted" way to write this code.
Any help/input with the code in AccountRequestHandler would be appreciated, especially with explanations of the rationale behind the recommend change(s).
Router implementation (stripped down to only "POST")...
#Configuration
public class AccountRequestRouter {
#Bean
public RouterFunction<ServerResponse> route(AccountRequestHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
.andRoute(RequestPredicates.POST("/accounts"), requestHandler::addAccount)
));
}
}
Handler implementation...
The code where I'm actually doing the add, and then separately creating a ServerResponse, is what I'm focused on. It seems "clunky", especially since AccountService.addAccount() returns a Mono on completion.
#Component
public class AccountRequestHandler {
#Autowired
private mil.navy.ccop.service.accounts.account.AccountService accountService;
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class).flatMap(account -> {
accountService.addAccount(account);
return ServerResponse.ok().build();
})
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build(Mono.empty()));
}
}
AccountService implementation (again, stripped down)...
#Service
class AccountService {
#Autowired
private AccountRepository accounts;
public AccountService() {
}
public Mono<Void> addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
return Mono.empty();
}
}
Appreciating all the help in ramping up on this style of programming....
well first of all, you have 2 addAccount, that can be a bit confusing.
Second of all, what kind of "repository" are you writing too? if its an sql repo you need to properly wrap it in a Mono.fromCallable() otherwise it will block the Reactive thread pool and you can have really bad performance.
Yes there are other ways of doing things. A lot of people tend to do things in flatmap or map and sure it is completely possible to do things here, but for the semantics i'd say it is less good.
map and flatmap are usually used to perform some sort of computation on the inner value of the mono and then return the same or a new value and or type inside the mono.
i would rewrite this like such.
return void here:
public void addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
}
And here:
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class)
.doOnSuccess(account -> {
accountService.addAccount(account);
}).then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build());
}
there are a number of different doOn methods that are ment to be used to consume and do "side effects" on things. Like doOnSuccess, doOnError, doOnCancel etc. etc.
you also have then and thenReturn which will just return whatever you put in them. Then returns whatever Mono you put in it. thenReturn wraps whatever value you put into it into a Mono and returns it.
In my ASP.Net CORE 2.2/EF Core 2.2 web API app, I have a HasData() method in my DbContext to seed the DB with some standard data that I use. However, I don't want to use that data when running my xUnit tests.
My unit tests use the Sqlite in-memory provider and as part of that process, it requires a call to EnsureCreated(). Well, EnsureCreated() calls OnModelCreating() which calls HasData(), so my unit test context now contains all of my HasData seed data, which I don't want. I want to seed my unit tests with different, very specific data.
Because EnsureCreated() seeds the context, and then I try adding my unit test specific seed data, I end up with both sets of data in my test DbContext and my tests fail.
How can I bypass the HasData call for my unit tests?
Instead of trying to bypass HasData(), you could instead conditionally not supply data to that method.
Quick example - if you move the pre-pop data out to e.g. "DataInitialiser" classes:
builder.HasData(new UserDataInitialiser().Data);
Then set a static flag in a base class:
public abstract class DataInitialiserControl
{
public static bool SkipInitData { get; set; } // ** flag **
}
public abstract class DataInitialiser<T> : DataInitialiserControl
{
public IList<T> Data => SkipInitData ? new List<T>() : GetData();
protected abstract IList<T> GetData();
}
Your DataInitialisers would look like this:
public class UserDataInitialiser : DataInitialiser<User>
{
protected override IList<User> GetData()
{
return new[]
{
new User {Id = 1, Name = "Bob"}
};
}
}
You could then just set the static flag in your test initialisation:
public abstract class TestBase
{
protected DbContextOptions<MyContext> DbOptions { get; private set; }
[TestInitialize]
public void InitializeDatabase()
{
// ** SKIP DATA PRE-POP **
DataInitialiserControl.SkipInitData = true;
DbOptions = BuildDbContextOptions(new DbContextOptionsBuilder<MyContext>()).Options;
using (var context = GetContext())
{
context.Database.EnsureCreated();
}
}
[TestCleanup]
public void ClearDatabase()
{
using (var context = GetContext())
{
context.Database.EnsureDeleted();
}
}
}
(Code untested, but should be more or less right).
You could always mock the call with Mock it will provides a way to mock an interface making it so the function calls of the said mocked interface will actually be calling your mocked function. This will provide a way for you to override the function call to HasData.
Of course, this means if it isn't already using an interface for that function(s) you'll have to wrap it in one.
Here are a few useful examples to Mocking: writing unit tests with NUnit and Moq and an introduction to unit testing with mocks(using moq).
I also suspect that Theory attribute and inline data could be of use to you.
Creating parameterized tests in xUnit
Hope that helps.
I am creating a small proof of concept asp.net web api 2 service with entity framework code first. The controller's constructor looks like
public AccountController: ApiController
{
private readonly DbContext context;
public AccountController(DbContext _context){
context = _context;
}
public AccountController(){context = new ApplicationContext();}
}
I need to unit test my controllers. How can I mock the DbContext class. Is there a simple way of doing this? I want to avoid all that repository pattern with lot of interfaces. Because it will be a way overkill for this prototype.
Its usually something like this if you use Nunit and Moq.
[TestFixture]
public class AccountControllerTest
{
private Mock<DbContext> mockContext;
private AccountController sut;
[SetUp]
public void TestSetup()
{
mockContext = new Mock<DbContext>();
var account = new Account() { Id = 123, Name = "Test Account" };
mockContext.SetUp(x => x.GetAccountOnContext()).Returns(account);
sut = new Controller(mockContext.Object) { Request = new HttpRequestMessage() };
sut.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
}
[Test]
public void ControllerMethod_GetLogin_Test()
{
// assuming GetLogin calls GetAccount on DbContext()
var response = sut.GetLogin(someAccount);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
mockContext.Verify();
}
}
You basically want to mock out your external dependencies and test just what the SUT (System Under Test) is supposed to do. I would also strongly encourage to look at Fakes instead of mocks. In general fakes result in less brittle tests.
So in this case, you could have a FakeDbContext() that you can pass to the tests. The FakeDbContext() will behave more like the actual DbContext() but will do all those operations in-memory, so that your tests don't have a dependency with a real database.
Depending on the database you use, you can also look at starting an embedded version of the real database as a part of your tests. Just have to make sure to do the necessary stopping and clean up of the test database records after the test run is complete in the TearDown() method.
I have an ASP.NET website project that until recent had all code in App_Code folder. It uses Entity Framework 4 as ORM. Application is divided into three "sections" (let's say one for each customer). Each section has it's own database (but same schema). This is due to performance reasons, databases are over 10GB each with millions of rows.
Each time a context object is created a Session variable which holds section ID is called and proprietary connection string is chosen for this context.
It looks like this (following are members of static Connection class):
public static MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
{
HttpContext.Current.Response.Redirect("~/Login.aspx");
}
var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
It works very good and also handles situation when session timed out everytime any data access is performed.
Recently as I needed to share DB classes among two websites I moved all DB classes to separate class library and referenced System.Web library which I know is bad practice, but it's working.
Now the next step is to include unit and module tests which as I read is very difficult or impossible when using HttpContext in library, so I want to get rid of System.Web references. What is the best practice for this situation?
I think I can't just pass HttpContext to GetEntityContext() as it is also called from within my entity classes. Although this probably can be refactored. So maybe this is where I should go?
I also wondered if is it possible to somehow pass current section ID to this whole library? It cannot be just static property because as far as I understand it would be common for all users using the application. This should be user-specific.
Reassuming the objective is to make automated testing possible without loosing transparent Connection String choosing and session timeouts handling.
If I do something fundamentally wrong at this stage please also let me know. I can look again at this question tomorrow morning (8.00 am UTC) so please don't be discouraged by my silence till then.
EDIT:
Example of usage of Connection class in the library:
public partial class Store
{
public static List<Store> GetSpecialStores()
{
using (var context = Connection.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
You can declare interface IContextProvider inside your library ans use it to retrieve context. Something like:
public interface IContextProvider
{
MyEntities GetEntityContext();
}
This will make your library testable. In your web project you can inject IContextProvider implementation into your library.
public class WebContextProvider : IContextProvider
{
public MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
HttpContext.Current.Response.Redirect("~/Login.aspx");
int sectionId = (int)HttpContext.Current.Session["section"];
string connectionString = GetEntityConnectionStringForSection(sectionId);
var context = new MyEntities(connectionString);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
}
Inject this interface to repositories or other data access classes.
public partial class Store
{
private IContextProvider contextProvider;
public Store(IContextProvider contextProvider)
{
this.contextProvider = contextProvider;
}
public List<Store> GetSpecialStores()
{
using (var context = contextProvider.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}