Unit testing Flashcards

1
Q

Different types of tests

A

integration tests, web tests, load tests, unit tests and others.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Test Driven Development (TDD)

A

Test Driven Development (TDD) is when a unit test is written before the code it is meant to check. TDD is like creating an outline for a book before we write it. It is meant to help developers write simpler, more readable, and efficient code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Do and Donts

A

Try not to introduce dependencies on infrastructure when writing unit tests. These make the tests slow and brittle, and should be reserved for integration tests. You can avoid these dependencies in your application by following the Explicit Dependencies Principle and using Dependency Injection. You can also keep your unit tests in a separate project from your integration tests. This ensures your unit test project doesn’t have references to or dependencies on infrastructure packages.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What are unit tests?

A

Having automated tests is a great way to ensure a software application does what its authors intend it to do. There are multiple types of tests for software applications. These include integration tests, web tests, load tests, and others. Unit tests test individual software components and methods. Unit tests should only test code within the developer’s control. They should not test infrastructure concerns. Infrastructure concerns include databases, file systems, and network resources.

.NET Core 2.0 and later supports .NET Standard 2.0, and we will use its libraries to demonstrate unit tests.

You are able to use built-in .NET Core 2.0 and later unit test project templates for C#, F# and Visual Basic as a starting point for your personal project.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Integration tests

A

Try not to introduce dependencies on infrastructure when writing unit tests. These make the tests slow and brittle, and should be reserved for integration tests.

Infrastructure concerns include databases, file systems, and network resources.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Why unit test?

A

Less time performing functional tests:
Functional tests are expensive. They typically involve opening up the application and performing a series of steps that you (or someone else), must follow in order to validate the expected behavior. These steps may not always be known to the tester, which means they will have to reach out to someone more knowledgeable in the area in order to carry out the test. Testing itself could take seconds for trivial changes, or minutes for larger changes. Lastly, this process must be repeated for every change that you make in the system.

Unit tests, on the other hand, take milliseconds, can be run at the press of a button and do not necessarily require any knowledge of the system at large. Whether or not the test passes or fails is up to the test runner, not the individual.

Protection against regression:
Regression defects are defects that are introduced when a change is made to the application. It is common for testers to not only test their new feature but also features that existed beforehand in order to verify that previously implemented features still function as expected.

With unit testing, it’s possible to rerun your entire suite of tests after every build or even after you change a line of code. Giving you confidence that your new code does not break existing functionality.

Executable documentation:
It may not always be obvious what a particular method does or how it behaves given a certain input. You may ask yourself: How does this method behave if I pass it a blank string? Null?

When you have a suite of well-named unit tests, each test should be able to clearly explain the expected output for a given input. In addition, it should be able to verify that it actually works.

Less coupled code:
When code is tightly coupled, it can be difficult to unit test. Without creating unit tests for the code that you’re writing, coupling may be less apparent.

Writing tests for your code will naturally decouple your code, because it would be more difficult to test otherwise.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Characteristics of a good unit test

A

Fast. It is not uncommon for mature projects to have thousands of unit tests. Unit tests should take very little time to run. Milliseconds.
Isolated. Unit tests are standalone, can be run in isolation, and have no dependencies on any outside factors such as a file system or database.
Repeatable. Running a unit test should be consistent with its results, that is, it always returns the same result if you do not change anything in between runs.
Self-Checking. The test should be able to automatically detect if it passed or failed without any human interaction.
Timely. A unit test should not take a disproportionately long time to write compared to the code being tested. If you find testing the code taking a large amount of time compared to writing the code, consider a design that is more testable.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Fake

A

A fake is a generic term which can be used to describe either a stub or a mock object. Whether it is a stub or a mock depends on the context in which it’s used. So in other words, a fake can be a stub or a mock.

The main thing to remember about mocks versus stubs is that mocks are just like stubs, but you assert against the mock object, whereas you do not assert against a stub.

https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Mock - a type of Fake object

A

A mock object is a fake object in the system that decides whether or not a unit test has passed or failed. A mock starts out as a Fake until it is asserted against.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Stub - a type of Fake object

A

A stub is a controllable replacement for an existing dependency (or collaborator) in the system. By using a stub, you can test your code without dealing with the dependency directly. By default, a fake starts out as a stub.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Wrong usage of stub as Mock

A
var mockOrder = new MockOrder();
var purchase = new Purchase(mockOrder);

purchase.ValidateOrders();

Assert.True(purchase.CanBeShipped);
This would be an example of stub being referred to as a mock. In this case, it is a stub. You’re just passing in the Order as a means to be able to instantiate Purchase (the system under test). The name MockOrder is also very misleading because again, the order is not a mock.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Stub example

A
var stubOrder = new FakeOrder();
var purchase = new Purchase(stubOrder);

purchase.ValidateOrders();

Assert.True(purchase.CanBeShipped);
By renaming the class to FakeOrder, you've made the class a lot more generic, the class can be used as a mock or a stub. Whichever is better for the test case. In the above example, FakeOrder is used as a stub. You're not using the FakeOrder in any shape or form during the assert. FakeOrder was just passed into the Purchase class to satisfy the requirements of the constructor.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Mock example

A
var mockOrder = new FakeOrder();
var purchase = new Purchase(mockOrder);

purchase.ValidateOrders();

Assert.True(mockOrder.Validated);
In this case, you are checking a property on the Fake (asserting against it), so in the above code snippet, the mockOrder is a Mock.

It’s important to get this terminology correct. If you call your stubs “mocks”, other developers are going to make false assumptions about your intent.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

mocks versus stubs

A

The main thing to remember about mocks versus stubs is that mocks are just like stubs, but you assert against the mock object, whereas you do not assert against a stub.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Best Practices:Naming your tests

A

The name of your test should consist of three parts:

1:The name of the method being tested.
2:The scenario under which it’s being tested.
3:The expected behavior when the scenario is invoked.
Why?
Naming standards are important because they explicitly express the intent of the test.
Tests are more than just making sure your code works, they also provide documentation. Just by looking at the suite of unit tests, you should be able to infer the behavior of your code without even looking at the code itself. Additionally, when tests fail, you can see exactly which scenarios do not meet your expectations.

Bad:
C#

Copy
[Fact]
public void Test_Single()
{
    var stringCalculator = new StringCalculator();
var actual = stringCalculator.Add("0");
    Assert.Equal(0, actual);
}
------
Better:
C#

Copy
[Fact]
public void Add_SingleNumber_ReturnsSameNumber()
{
var stringCalculator = new StringCalculator();

var actual = stringCalculator.Add("0");

Assert.Equal(0, actual); } Arranging your tests Arrange, Act, Assert is a common pattern when unit testing. As the name implies, it consists of three main actions:

Arrange your objects, creating and setting them up as necessary.
Act on an object.
Assert that something is as expected.
Why?
Clearly separates what is being tested from the arrange and assert steps.
Less chance to intermix assertions with “Act” code.
Readability is one of the most important aspects when writing a test. Separating each of these actions within the test clearly highlight the dependencies required to call your code, how your code is being called, and what you are trying to assert. While it may be possible to combine some steps and reduce the size of your test, the primary goal is to make the test as readable as possible.

Bad:
C#

Copy
[Fact]
public void Add_EmptyString_ReturnsZero()
{
// Arrange
var stringCalculator = new StringCalculator();

    // Assert
    Assert.Equal(0, stringCalculator.Add(""));
}
Better:
C#

Copy
[Fact]
public void Add_EmptyString_ReturnsZero()
{
// Arrange
var stringCalculator = new StringCalculator();

    // Act
    var actual = stringCalculator.Add("");
    // Assert
    Assert.Equal(0, actual);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Best Practices:Arranging your tests -Arrange, Act, Assert

A

Arrange, Act, Assert is a common pattern when unit testing. As the name implies, it consists of three main actions:

Arrange your objects, creating and setting them up as necessary.
Act on an object.
Assert that something is as expected.
Why?
Clearly separates what is being tested from the arrange and assert steps.
Less chance to intermix assertions with “Act” code.
Readability is one of the most important aspects when writing a test. Separating each of these actions within the test clearly highlight the dependencies required to call your code, how your code is being called, and what you are trying to assert. While it may be possible to combine some steps and reduce the size of your test, the primary goal is to make the test as readable as possible.

Bad:
C#

Copy
[Fact]
public void Add_EmptyString_ReturnsZero()
{
// Arrange
var stringCalculator = new StringCalculator();

    // Assert
    Assert.Equal(0, stringCalculator.Add(""));
}
Better:
C#

Copy
[Fact]
public void Add_EmptyString_ReturnsZero()
{
// Arrange
var stringCalculator = new StringCalculator();

    // Act
    var actual = stringCalculator.Add("");
    // Assert
    Assert.Equal(0, actual);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Best Practices:Write minimally passing tests

A

The input to be used in a unit test should be the simplest possible in order to verify the behavior that you are currently testing.

Why?
Tests become more resilient to future changes in the codebase.
Closer to testing behavior over implementation.
Tests that include more information than required to pass the test have a higher chance of introducing errors into the test and can make the intent of the test less clear. When writing tests you want to focus on the behavior. Setting extra properties on models or using non-zero values when not required, only detracts from what you are trying to prove.

Bad:
C#

Copy
[Fact]
public void Add_SingleNumber_ReturnsSameNumber()
{
var stringCalculator = new StringCalculator();

var actual = stringCalculator.Add("42");

Assert.Equal(42, actual); } Better: C#

Copy
[Fact]
public void Add_SingleNumber_ReturnsSameNumber()
{
var stringCalculator = new StringCalculator();

var actual = stringCalculator.Add("0");

Assert.Equal(0, actual); }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Best Practices:Avoid magic strings

A

Naming variables in unit tests is as important, if not more important, than naming variables in production code. Unit tests should not contain magic strings.

Why?
Prevents the need for the reader of the test to inspect the production code in order to figure out what makes the value special.
Explicitly shows what you’re trying to prove rather than trying to accomplish.
Magic strings can cause confusion to the reader of your tests. If a string looks out of the ordinary, they may wonder why a certain value was chosen for a parameter or return value. This may lead them to take a closer look at the implementation details, rather than focus on the test.

Tip

When writing tests, you should aim to express as much intent as possible. In the case of magic strings, a good approach is to assign these values to constants.

Bad:
C#

Copy
[Fact]
public void Add_BigNumber_ThrowsException()
{
var stringCalculator = new StringCalculator();

Action actual = () => stringCalculator.Add("1001");

Assert.Throws(actual); } Better: C#

Copy
[Fact]
void Add_MaximumSumResult_ThrowsOverflowException()
{
var stringCalculator = new StringCalculator();
const string MAXIMUM_RESULT = “1001”;

Action actual = () => stringCalculator.Add(MAXIMUM_RESULT);

Assert.Throws(actual); }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Best Practices:Avoid logic in tests

A

When writing your unit tests avoid manual string concatenation and logical conditions such as if, while, for, switch, etc.

Why?
Less chance to introduce a bug inside of your tests.
Focus on the end result, rather than implementation details.
When you introduce logic into your test suite, the chance of introducing a bug into it increases dramatically. The last place that you want to find a bug is within your test suite. You should have a high level of confidence that your tests work, otherwise, you will not trust them. Tests that you do not trust, do not provide any value. When a test fails, you want to have a sense that something is actually wrong with your code and that it cannot be ignored.

Tip

If logic in your test seems unavoidable, consider splitting the test up into two or more different tests.

Bad:
C#

Copy
[Fact]
public void Add_MultipleNumbers_ReturnsCorrectResults()
{
    var stringCalculator = new StringCalculator();
    var expected = 0;
    var testCases = new[]
    {
        "0,0,0",
        "0,1,2",
        "1,2,3"
    };
    foreach (var test in testCases)
    {
        Assert.Equal(expected, stringCalculator.Add(test));
        expected += 3;
    }
}
Better:
C#
Copy
[Theory]
[InlineData("0,0,0", 0)]
[InlineData("0,1,2", 3)]
[InlineData("1,2,3", 6)]
public void Add_MultipleNumbers_ReturnsSumOfNumbers(string input, int expected)
{
    var stringCalculator = new StringCalculator();
var actual = stringCalculator.Add(input);

Assert.Equal(expected, actual); }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Best Practices:Prefer helper methods to setup and teardown

A

If you require a similar object or state for your tests, prefer a helper method than leveraging Setup and Teardown attributes if they exist.

Why?
Less confusion when reading the tests since all of the code is visible from within each test.
Less chance of setting up too much or too little for the given test.
Less chance of sharing state between tests which creates unwanted dependencies between them.
In unit testing frameworks, Setup is called before each and every unit test within your test suite. While some may see this as a useful tool, it generally ends up leading to bloated and hard to read tests. Each test will generally have different requirements in order to get the test up and running. Unfortunately, Setup forces you to use the exact same requirements for each test.

Note

xUnit has removed both SetUp and TearDown as of version 2.x

Bad:
C#

Copy
private readonly StringCalculator stringCalculator;
public StringCalculatorTests()
{
stringCalculator = new StringCalculator();
}
C#

Copy
// more tests…
C#

Copy
[Fact]
public void Add_TwoNumbers_ReturnsSumOfNumbers()
{
var result = stringCalculator.Add(“0,1”);

    Assert.Equal(1, result);
}
----
Better:
C#

Copy
[Fact]
public void Add_TwoNumbers_ReturnsSumOfNumbers()
{
var stringCalculator = CreateDefaultStringCalculator();

var actual = stringCalculator.Add("0,1");

Assert.Equal(1, actual); } C#

Copy
// more tests…
C#

Copy
private StringCalculator CreateDefaultStringCalculator()
{
    return new StringCalculator();
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Best Practices:Avoid multiple asserts

A

When writing your tests, try to only include one Assert per test. Common approaches to using only one assert include:

Create a separate test for each assert.
Use parameterized tests.
Why?
If one Assert fails, the subsequent Asserts will not be evaluated.
Ensures you are not asserting multiple cases in your tests.
Gives you the entire picture as to why your tests are failing.
When introducing multiple asserts into a test case, it is not guaranteed that all of the asserts will be executed. In most unit testing frameworks, once an assertion fails in a unit test, the proceeding tests are automatically considered to be failing. This can be confusing as functionality that is actually working, will be shown as failing.

Note

A common exception to this rule is when asserting against an object. In this case, it is generally acceptable to have multiple asserts against each property to ensure the object is in the state that you expect it to be in.

Bad:
C#

Copy
[Fact]
public void Add_EdgeCases_ThrowsArgumentExceptions()
{
Assert.Throws(() => stringCalculator.Add(null));
Assert.Throws(() => stringCalculator.Add(“a”));
}
Better:
C#

Copy
[Theory]
[InlineData(null)]
[InlineData(“a”)]
public void Add_InputNullOrAlphabetic_ThrowsArgumentException(string input)
{
var stringCalculator = new StringCalculator();

Action actual = () => stringCalculator.Add(input);

Assert.Throws(actual); }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Best Practices:Validate private methods by unit testing public methods

A

In most cases, there should not be a need to test a private method. Private methods are an implementation detail. You can think of it this way: private methods never exist in isolation. At some point, there is going to be a public facing method that calls the private method as part of its implementation. What you should care about is the end result of the public method that calls into the private one.

Consider the following case

C#

Copy
public string ParseLogLine(string input)
{
    var sanitizedInput = TrimInput(input);
    return sanitizedInput;
}
private string TrimInput(string input)
{
    return input.Trim();
}
Your first reaction may be to start writing a test for TrimInput because you want to make sure that the method is working as expected. However, it is entirely possible that ParseLogLine manipulates sanitizedInput in such a way that you do not expect, rendering a test against TrimInput useless.

The real test should be done against the public facing method ParseLogLine because that is what you should ultimately care about.

C#

Copy
public void ParseLogLine_ByDefault_ReturnsTrimmedResult()
{
    var parser = new Parser();
var result = parser.ParseLogLine(" a ");

Assert.Equals("a", result); } With this viewpoint, if you see a private method, find the public method and write your tests against that method. Just because a private method returns the expected result, does not mean the system that eventually calls the private method uses the result correctly.
23
Q

Best Practices:Stub static references

A

One of the principles of a unit test is that it must have full control of the system under test. This can be problematic when production code includes calls to static references (e.g. DateTime.Now). Consider the following code

C#

Copy
public int GetDiscountedPrice(int price)
{
    if(DateTime.Now.DayOfWeek == DayOfWeek.Tuesday) 
    {
        return price / 2;
    }
    else 
    {
        return price;
    }
}
How can this code possibly be unit tested? You may try an approach such as

C#

Copy
public void GetDiscountedPrice_ByDefault_ReturnsFullPrice()
{
    var priceCalculator = new PriceCalculator();
var actual = priceCalculator.GetDiscountedPrice(2);

Assert.Equals(2, actual) }
public void GetDiscountedPrice_OnTuesday_ReturnsHalfPrice()
{
    var priceCalculator = new PriceCalculator();
var actual = priceCalculator.GetDiscountedPrice(2);

Assert.Equals(1, actual); } Unfortunately, you will quickly realize that there are a couple problems with your tests.

If the test suite is run on a Tuesday, the second test will pass, but the first test will fail.
If the test suite is run on any other day, the first test will pass, but the second test will fail.
To solve these problems, you’ll need to introduce a seam into your production code. One approach is to wrap the code that you need to control in an interface and have the production code depend on that interface.

C#

Copy
public interface IDateTimeProvider
{
    DayOfWeek DayOfWeek();
}
public int GetDiscountedPrice(int price, IDateTimeProvider dateTimeProvider)
{
    if(dateTimeProvider.DayOfWeek() == DayOfWeek.Tuesday) 
    {
        return price / 2;
    }
    else 
    {
        return price;
    }
}
Your test suite now becomes

C#

Copy
public void GetDiscountedPrice_ByDefault_ReturnsFullPrice()
{
var priceCalculator = new PriceCalculator();
var dateTimeProviderStub = new Mock();
dateTimeProviderStub.Setup(dtp => dtp.DayOfWeek()).Returns(DayOfWeek.Monday);

var actual = priceCalculator.GetDiscountedPrice(2, dateTimeProviderStub);

Assert.Equals(2, actual); }
public void GetDiscountedPrice_OnTuesday_ReturnsHalfPrice()
{
    var priceCalculator = new PriceCalculator();
    var dateTimeProviderStub = new Mock();
    dateTimeProviderStub.Setup(dtp => dtp.DayOfWeek()).Returns(DayOfWeek.Tuesday);
var actual = priceCalculator.GetDiscountedPrice(2, dateTimeProviderStub);

Assert.Equals(1, actual); } Now the test suite has full control over DateTime.Now and can stub any value when calling into the method.
24
Q

Unit Testing Frameworks: XUnit vs. NUnit vs. MSTEST for .NET and .NET Core

A

https://medium.com/@robinding/unit-testing-frameworks-xunit-vs-nunit-vs-mstest-for-net-and-net-core-e526011c0bd2

25
Q

.Net core vs Asp.net Core testing

A

unit test project .NET Core project. If you’re testing an ASP.NET Core project, see Integration tests in ASP.NET Core.

26
Q

Process for writing tests

A

You write one failing test, make it pass, then repeat the process

27
Q

TestClass attribute in MS test

A

The TestClass attribute denotes a class that contains unit tests.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Prime.Services;

namespace Prime.UnitTests.Services
{
[TestClass]
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;

        public PrimeService_IsPrimeShould()
        {
            _primeService = new PrimeService();
        }
        [TestMethod]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var result = _primeService.IsPrime(1);
        Assert.IsFalse(result, "1 should not be prime");
    }
} }
28
Q

TestMethod attribute

A

The TestMethod attribute indicates a method is a test method.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Prime.Services;

namespace Prime.UnitTests.Services
{
[TestClass]
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;

        public PrimeService_IsPrimeShould()
        {
            _primeService = new PrimeService();
        }
        [TestMethod]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var result = _primeService.IsPrime(1);
        Assert.IsFalse(result, "1 should not be prime");
    }
} }
29
Q

DataTestMethod attribute and DataRow attribute

A

A DataTestMethod attribute represents a suite of tests that execute the same code but have different input arguments. You can use the DataRow attribute to specify values for those inputs.

Instead of creating new tests, apply these two attributes to create a single data driven test. The data driven test is a method that tests several values less than two, which is the lowest prime number:

C#

Copy
[DataTestMethod]
[DataRow(-1)]
[DataRow(0)]
[DataRow(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);
Assert.IsFalse(result, $"{value} should not be prime"); }
30
Q

Mocking with Moq

A

Mock objects allow you to mimic the behavior of classes and interfaces, letting the code in the test interact with them as if they were real. This isolates the code you’re testing, ensuring that it works on its own and that no other code will make the tests fail.

With mocks, you can set up the object, including giving parameters and return values on method calls and setting properties. You can also verify that the methods you set up are being called in the tested code. This ensures that the flow of the program is as expected

31
Q

Moq Loose and Strict behavior

A

We can also give it strict or loose behavior. Strict behavior means that exceptions will be thrown if anything that was not set up on our interface is called. Loose behavior, on the other hand, does not throw exceptions in situations like this. Mocks, by default, are loose.

32
Q

unit test

A

our tests should not be impacted if the database is down or because of any external dependecies

33
Q

Moq is a proxy that has behavior

A

You need to call getCustomers() on this moq but only call once. we could setup the Moq to report that and record that and throw an exception, if it is called twice

34
Q

using Moq in the project

A

add Nuget package Moq in your unit test project either Xunit or Nunit or MStest

35
Q

Creating a Moq around something

A
var mock= new Mock(); 
we are creating a Mock for IRepo interface
we could also Mock for concrete classes but it is little complex; we should be Mocking an interface
36
Q

setting up the Moq

A
INTERFACT TO GET THE DATA:
public interface IRepo
{
Customer Find(int id);
}
this interface has a method called "Find", this takes id as the parameter and returns Customer object
----------
UNIT TEST PROJECT:
[Fact]
public void Should_Mock_Function_With_Return_Value()
{
//ARRANGE
var id=12;
var name="Fred Flinstone";
var customer = new Customer{Id=id,Name=name};
var mock= new Mock();
mock.Setup(x=>x.Find(id)).Returns(customer);
//we are looking for find method; when we pass id then we are getting customer
var controller = new TestController(mock.object);
//instance of IRepo
//ACT
var actual=controller.GetCustomer(id);

}

//ASSERT
Assert.Same(customer,actual);
Assert.Equal(id,actual.id);
Assert.Equal(name,actual.Name);
-----------------
CONTROLLER:
//Controller; this requires instance of IRepo in the constructor
class TestController
{
public TestController(IRepo repo)
{
_repo= repo; //setting the repo to use; in our case the Moq
}
Public Customer GetCustomer(int id)
{
try
{
return _repo.Find(id);
}
}
}
37
Q

mock.setupSequence example

A

UNIT TEST PROJECT:
[TestMethod]
public void GetCustomer_CheckForMultipleCustomers_ReturnsCustomerobject()
{

            //ARRANGE
            var id1 = 12;
            var id3=14;
            var name1 = "john";
            var customer1 = new Customer
            {
                Id = id1,
                Name = name1
            };
            var id2 = 13;
            //var id1=13;
            var name2 = "Peter";
            var customer2 = new Customer
            {
                Id = id2,
                Name = name2
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
        //Setting up the definition for one of the IRepo interface method; to say what is the input and
        //what is the expected output 
        //This means that for the first integer(any) passed in we get customer1 and for the second integer (any) passed in we get the customer2
        mock.SetupSequence(x => x.Find(It.IsAny()))
            .Returns(customer1)
            .Returns(customer2);
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
        //ACT

        var actual1 = controller.GetCustomer(id1);//Here we could pass any ID value but we get the first object from the MOCK

        //ASSERT

        Assert.AreEqual(id1, actual1.Id);
        Assert.AreEqual(name1, actual1.Name);

        var actual2 = controller.GetCustomer(id2);//Here we could pass any ID value but we get the second object from the MOCK

        //ASSERT

        Assert.AreEqual(id2, actual2.Id);
        Assert.AreEqual(name2, actual2.Name);

    }
38
Q

Verifiable - it gives incredible power of how the Mock behaves

A

Verifiable - it gives incredible power of how the Mock behaves

https://codingcanvas.com/moq-setup-verify-verifiable-callback-explained/

[TestMethod]
public void AddIncomePeriod_ShouldCallRepository_WithCorrectIncomePeriod()

{
var newIncomePeriod = new IncomePeriod
{

Id = 3333,

StartDate = new DateTime(2019, 9, 1),

EndDate = new DateTime(2019, 9, 30),

Primary = 10000,

Additional = 500,

Name = “September”,

User = new User

{

Id = testUserId1

}

};

mockRepository.Setup(x =>; x.GetIncomePeriods()).Returns(mockIncomePeriods.AsQueryable());

mockRepository.Setup(x =>; x.AddIncomePeriod(It.IsAny())).Returns(x => x).Verifiable();

var service = new IncomePeriodService(mockRepository.Object);

var result = service.AddIncomePeriod(newIncomePeriod);

mockRepository.Verify(x => x.AddIncomePeriod(newIncomePeriod));

}
mockRepository.Setup(x => x.AddIncomePeriod(It.IsAny())).Returns(x => x).Verifiable();

‘Setup’ mocks a method and ‘Returns’ specify what the mocked method should return.
‘Verifiable’ marks this expectation to verified at the end when Verify or VerifyAll is called i.e. whether AddIncomePeriod was called with an object of IncomePeriod and if it returned the same output.

39
Q

Moq - Setting up a mock repo with a definition for its interface method

A

[TestMethod]
public void GetCustomer_CheckForSpecificCustomer_ReturnsCustomerobject()
{

            //ARRANGE
            var id = 12;
           //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
        //Setting up the definition for one of the IRepo interface method; to say what is the input and
        //what is the expected output 
            mock.Setup(x => x.Find(id)).Returns(customer);
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id);
        //ASSERT
   //     Assert.AreSame(customer, actual);
        Assert.AreEqual(id, actual.Id);
        Assert.AreEqual(name,actual.Name);

    }
40
Q

Moq - SetupSequence - for setting multiple values to pass

A

[TestMethod]
public void GetCustomer_CheckForMultipleCustomers_ReturnsCustomerobject()
{

            //ARRANGE
            var id1 = 12;
            var id3=14;
            var name1 = "john";
            var customer1 = new Customer
            {
                Id = id1,
                Name = name1
            };
            var id2 = 13;
            //var id1=13;
            var name2 = "Peter";
            var customer2 = new Customer
            {
                Id = id2,
                Name = name2
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
        //Setting up the definition for one of the IRepo interface method; to say what is the input and
        //what is the expected output 
        //This means that for the first integer(any) passed in we get customer1 and for the second integer (any) passed in we get the customer2
        mock.SetupSequence(x => x.Find(It.IsAny()))
            .Returns(customer1)
            .Returns(customer2);
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
        //ACT
            var actual1 = controller.GetCustomer(id1);//Here we could pass any ID value but we get the first object from the MOCK
            //Even if in the above GetCustomer method Find(id) is called twice then the Mock values are being read one after the other
        //ASSERT

        Assert.AreEqual(id1, actual1.Id);
        Assert.AreEqual(name1, actual1.Name);

        var actual2 = controller.GetCustomer(id2);//Here we could pass any ID value but we get the second object from the MOCK

        //ASSERT

        Assert.AreEqual(id2, actual2.Id);
        Assert.AreEqual(name2, actual2.Name);

    }
41
Q

Moq - to verify if the mock method is called atleast once

A
[TestMethod]
        public void GetCustomer_FindMethodShouldbeCalledAtleastOnce_Verfiable()
        {
            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up a call
            Expression> call = x => x.Find(id);
        mock.Setup(call).Returns(customer).Verifiable("Method not called");
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id);
        //ASSERT
        //     Assert.AreSame(customer, actual);
        Assert.AreEqual(id, actual.Id);
        Assert.AreEqual(name, actual.Name);
        mock.Verify(call);

    }
42
Q

moq - setting up a call to use with delegate

A
//Setting up a call
            Expression> call = x => x.Find(id);
        mock. Setup(call).Returns(customer).Verifiable("Method not called");    mock. Verify(call);
43
Q

Moq- to verify a method is called only once

A
[TestMethod]
        public void GetCustomer_FindMethodShouldbeCalledOnlyOnce_Verfiable() // this helps to make sure that we are not calling multiple times and hanging the database
        {
            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up a call once and using it later
            Expression> call = x => x.Find(id);
        mock.Setup(call).Returns(customer).Verifiable("Method not called"); //Verifiable makes it ready to be verified 
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id);
        //ASSERT
        //     Assert.AreSame(customer, actual);
        Assert.AreEqual(id, actual.Id);
        Assert.AreEqual(name, actual.Name);
        mock.Verify(call,Times.Once); //we have once, Never, Exactly 
        //Never is used when the call to an exception method should not occur in a particular scenario

    }
44
Q

Moq verify all

A

[TestMethod]
public void GetCustomer_CheckForSpecificCustomer_VerifyAll()
{

            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            mock.Setup(x => x.Find(id)).Returns(customer);
        //ASSERT

        Assert.ThrowsException(()=>mock.VerifyAll()); //Make sure everything behaves the way it should behave; but we loose the capability of it should be called 7 times etc

    }
45
Q

Moq check for Null values

A

[TestMethod]
public void GetCustomer_CheckForNullCustomerForInvalidID_ReturnsNull()
{

            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            mock.Setup(x => x.Find(id)).Returns(customer);
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id+1);
            //ASSERT
            //     Assert.AreSame(customer, actual);
            Assert.IsNull(actual);
        }
46
Q

Moq - check the return object for any integer passed

A
[TestMethod]
        public void GetCustomer_CheckReturnedCustomerForanyCustomerID_ReturnsCustomer()
        {
            //Some times we do not care about any specific customer retrieving; but test the behavior 
            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            //  Expression> call = x => x.Find(It.IsAny());
            //mock.Setup(call).Returns(customer);
              mock.Setup(x => x.Find(It.IsAny())).Returns(customer); //For Any customer id return customer
           //   mock.Setup(x => x.Find(It.Is(i => i>0))).Returns(customer); // For Customer ID >0 return customer
          //  mock.Setup(x => x.Find(It.IsInRange(0, 100, Range.Inclusive))).Returns(customer); - to return customer only when with in Range of Customer I
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id);
        //ASSERT
        //     Assert.AreSame(customer, actual);
        Assert.AreEqual(id, actual.Id);
        Assert.AreEqual(name, actual.Name);
    }
47
Q

Moq - setting up repo method for exception throwing

A
[TestMethod]
        public void GetCustomer_CheckForExceptionforInvalidCustomerID_ReturnsArgumentException()
        {
            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            mock.Setup(x => x.Find(id)).Throws();
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ASSERT
            //     Assert.AreSame(customer, actual);
            Assert.ThrowsException(()=> controller.GetCustomer(id));
        }
48
Q

Moq- setting up mock methods to throw general exception

A
[TestMethod]
        public void GetCustomer_DataLayerThrowsException_ReturnsError()
        {
            // setup
            //ARRANGE
            var id = 5;
            var id1 = 12;
            var id3 = 14;
            var name1 = "john";
            var customer1 = new Customer
            {
                Id = id1,
                Name = name1
            };
            var id2 = 13;
            //var id1=13;
            var name2 = "Peter";
            var customer2 = new Customer
            {
                Id = id2,
                Name = name2
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            //This means that for the first integer(any) passed in we get customer1 and for the second integer (any) passed in we get the customer2
            mock.Setup(x => x.Find(id)).Throws(new Exception());
            var controller = new TestController(mock.Object);
            // execute
            //  var result =  controller.GetCustomer(id);
            // assert
            Assert.ThrowsException(() => controller.GetCustomer(id));
        }
49
Q

Moq- setting the unit test to use [DataRow()] and return specific indexed object

A
[TestMethod]
        [DataRow(0,12, "Bob")]
        [DataRow(1, 17, "Sue")]
        [DataRow(2, 200, "Tony")]
        public void GetCustomer_CheckForSpecificCustomerFromAList_ReturnsIndexedCustomer(int index,int Customerid,string CustomerName)
        {
            //ARRANGE
            var customer = new List
            {
                new Customer{Id=12,Name="Bob"},
                new Customer{Id=17,Name="Sue"},
                new Customer{Id=200,Name="Tony"}
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
            //Setting up the definition for one of the IRepo interface method; to say what is the input and
            //what is the expected output 
            mock.Setup(x => x.Find(It.IsInRange(0,2,Range.Inclusive)))
                .Returns((int x)=>customer[x]);
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(index);
        //ASSERT
        //     Assert.AreSame(customer, actual);
        Assert.AreEqual(Customerid, actual.Id);
        Assert.AreEqual(CustomerName, actual.Name);
    }
50
Q

Moq - events- still need to understand

A
[TestMethod]
        public void FailedDatabaseRequest_checkifTheEventIsRaisedAndLoggerWorked_ReturnException()
        {
            //var mockRepo = new Mock();
            //var mockLogger = new Mock();
            //Expression> expression = x => x.LogError("An error occured");
            //mockLogger.Setup(expression).Verifiable();
            //var controller = new TestController(mockRepo.Object, mockLogger.Object);
            //mockRepo.Raise(m => m.FailedDatabseRequest += null, this, EventArgs.Empty);
            //mockLogger.Verify(expression);
    }
51
Q

Moq - using call backs

A
[TestMethod]
        public void GetCustomer_UsingCallBacks_ReturnsCustomer()
        {
            //ARRANGE
            var id = 12;
            //var id1=13;
            var name = "john";
            var customer = new Customer
            {
                Id = id,
                Name = name
            };
            //creating a Mock for the IRepo interface
            var mock = new Mock();
        //Setting up the definition for one of the IRepo interface method; to say what is the input and
        //what is the expected output 
        mock.Setup(x => x.Find(id))
            .Callback(() => Console.WriteLine("Before Execution"))
            .Returns(customer)
            .Callback(()=>Console.WriteLine("After Execution"));
            //Creating the instance of TestController with the Mock object implementation of IRepo
            //Here we are using the concept of Dependency Injection
            var controller = new TestController(mock.Object);
            //ACT
            //Calling the GetCustomer action method on the controller;it looks for ID in the created Moq and returns the customer object
            var actual = controller.GetCustomer(id);
        //ASSERT
        //     Assert.AreSame(customer, actual);
        Assert.AreEqual(id, actual.Id);
        Assert.AreEqual(name, actual.Name);
    }
52
Q

Customize Mock behavior - using loose and strict

A
[TestMethod]
        public void GetCustomer_TestingTheLooseMock_returnsNull()
        {
            var mockRepo = new  Mock(MockBehavior.Loose);
            var controller = new TestController(mockRepo.Object);
            var customer = controller.GetCustomer(12);
            Assert.IsNull(customer); //we have not done any setup for Find() method of IRepo which is used in GetCustomer() methods; despite throwing error it returns null
    }
        [TestMethod]
        //This is more for testing the behavior with System under test rather than the actual input and output
        public void GetCustomer_TestingTheStrictMock_returnsNull()
        {
           //anything not implemented like passing id to GetCustomer method which we have not set up or having _repo.addRecord method call in GetCustomer() method
            var mockRepo = new Mock(MockBehavior.Strict);
            var controller = new TestController(mockRepo.Object);
            var id = 12;
            var ex = Assert.ThrowsException(() => controller.GetCustomer(12));
            Assert.AreEqual($"IRepo.Find({id}) invocation failed with mock behavior Strict. \nAll invocations on the mock must have a corresponding setup.", ex.Message);
        }
53
Q

Moq - concrete class- not advisable - Need to understand better

A
//anything  that you want to expose through MOCK on a concrete class has to be marked virtual; as MOCK is creating proxy around the thing that we are mocking
        //the creation of proxy is easy with interfaces but difficult with concrete class unless the methods are marked virtual.
        //in concrete class it is deriving from the virtual method
        [TestMethod]
        //Do not mock concrete classes; but if you pulled legacy code then it might have it and know a way to work with it 
        //There are commercial versions available for mocking; if you follow the SOLID design principles then you do not need the commerical versions and you could do with free tools
        public void GetNumber_ToMockConcreteClassProtectedMembers_ReturnsInt()
        {
            //var mock = new Mock();
            //mock.Setup("GetNumber").Returns(12);
        }
54
Q

Moq - testing async methods examples

A
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using org.cchmc.pho.api.Controllers;
using org.cchmc.pho.api.Mappings;
using org.cchmc.pho.api.ViewModels;
using org.cchmc.pho.core.DataModels;
using org.cchmc.pho.core.Interfaces;
using org.cchmc.pho.core.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
namespace org.cchmc.pho.unittest.controllertests
{
    [TestClass]
    [ExcludeFromCodeCoverage]
    public class AlertControllerTests
    {
        private AlertController _alertController;
        private Mock> _mockLogger;
        private Mock _mockAlertDal;
        private Mock> _mockOptions;
        private IMapper _mapper;
        [TestInitialize]
        public void Initialize()
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.AddMaps(Assembly.GetExecutingAssembly());
                cfg.AddMaps(Assembly.GetAssembly(typeof(AlertMappings)));
            });
            _mapper = config.CreateMapper();
            _mockAlertDal = new Mock();
            _mockLogger = new Mock>();
            _mockOptions = new Mock>();
            //todo populate values later.
            _mockOptions.Setup(op => op.Value).Returns(new CustomOptions());
    }
        [TestMethod]
        public async Task ListActiveAlert_Mapping_Success()
        {
            // setup
            var userId = 5;
            var myAlerts = new List()
            {
                new Alert()
                {
                    AlertId = 1,
                    AlertScheduleId = 7,
                    Definition = "MyDefinition",
                    LinkText = "SomeLinks",
                    Message = "A Message",
                    Url = "http://www.example.com"
                },
                new Alert()
                {
                    AlertId = 3,
                    AlertScheduleId = 2,
                    Definition = "MyDefinition2",
                    LinkText = "SomeLinksasdf",
                    Message = "Aasdf Message",
                    Url = "http://www.example2.com"
                }
            };
            _mockAlertDal.Setup(p => p.ListActiveAlerts(userId)).Returns(Task.FromResult(myAlerts)).Verifiable();
            _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.ListActiveAlerts(userId.ToString()) as ObjectResult;
            var resultList = result.Value as List;
        // assert
        Assert.AreEqual(2, resultList.Count);
        Assert.AreEqual(myAlerts[0].AlertId, resultList[0].AlertId);
        Assert.AreEqual(myAlerts[0].AlertScheduleId, resultList[0].AlertScheduleId);
        Assert.AreEqual(myAlerts[0].Definition, resultList[0].Definition);
        Assert.AreEqual(myAlerts[0].LinkText, resultList[0].LinkText);
        Assert.AreEqual(myAlerts[0].Message, resultList[0].Message);
        Assert.AreEqual(myAlerts[0].Url, resultList[0].Url);
        Assert.AreEqual(myAlerts[1].AlertId, resultList[1].AlertId);
        Assert.AreEqual(myAlerts[1].AlertScheduleId, resultList[1].AlertScheduleId);
        Assert.AreEqual(myAlerts[1].Definition, resultList[1].Definition);
        Assert.AreEqual(myAlerts[1].LinkText, resultList[1].LinkText);
        Assert.AreEqual(myAlerts[1].Message, resultList[1].Message);
        Assert.AreEqual(myAlerts[1].Url, resultList[1].Url);

    }

    [TestMethod]
    public async Task ListActiveAlert_UserIdDoesNotValidate_Throws400()
    {
        // setup
        var userId = "asdf";
        _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.ListActiveAlerts(userId) as ObjectResult;
        // assert
        Assert.AreEqual(400, result.StatusCode);
        Assert.AreEqual("user is not a valid integer", result.Value);
        _mockAlertDal.Verify(p => p.ListActiveAlerts(It.IsAny()), Times.Never);
    }
        [TestMethod]
        public async Task ListActiveAlert_DataLayerThrowsException_ReturnsError()
        {
            // setup
            var userId = 5;
            _mockAlertDal.Setup(p => p.ListActiveAlerts(userId)).Throws(new Exception());
            _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.ListActiveAlerts(userId.ToString()) as ObjectResult;
            // assert
            Assert.AreEqual(500, result.StatusCode);
        }
        //[TestMethod]
        //public async Task ListActiveAlert_test_Return()
        //{
        //    // setup
        //    var userId = 5;
        //    Expression> call = x => x.ListActiveAlerts(userId);
        //    _mockAlertDal.Setup()
        //_alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
        //// execute
        //var result = await _alertController.ListActiveAlerts(userId.ToString()) as ObjectResult;
        //// assert
        //Assert.AreEqual(500, result.StatusCode);
        //}
        [TestMethod]
        public async Task MarkAlertAction_Success()
        {
            // setup
            var userId = 5;
            var alertSchedule = 7;
            var alertActionId = 9;
            var alertDateTime = DateTime.Parse("1/19/20");
        _mockAlertDal.Setup(p => p.MarkAlertAction(alertSchedule,userId, alertActionId))
            .Returns(Task.CompletedTask).Verifiable();
        _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.MarkAlertAction(alertSchedule.ToString(), userId.ToString(),  new AlertActionViewModel()
            {
                AlertActionId = alertActionId
            });
            // assert
            Assert.IsInstanceOfType(result, typeof(OkResult));
            var okResult = result as OkResult;
            Assert.AreEqual(200, okResult.StatusCode);
        }
        [TestMethod]
        public async Task MarkAlertAction_UserIdDoesNotValidate_Throws400()
        {
            // setup
            var userId = "asdf";
            var alertSchedule = 7;
            var alertActionId = 9;
            var alertDateTime = DateTime.Parse("1/19/20");
        _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.MarkAlertAction(alertSchedule.ToString(),userId.ToString(),new AlertActionViewModel()
            {
                AlertActionId = alertActionId
            }) as ObjectResult;
        // assert
        Assert.AreEqual(400, result.StatusCode);
        Assert.AreEqual("user is not a valid integer", result.Value);
        _mockAlertDal.Verify(p => p.MarkAlertAction(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
    }
        [TestMethod]
        public async Task MarkAlertAction_AlertScheduleDoesNotValidate_Throws400()
        {
            // setup
            var userId = 5;
            var alertSchedule = "asdf";
            var alertActionId = 9;
        _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.MarkAlertAction(alertSchedule.ToString(),userId.ToString(), new AlertActionViewModel()
            {
                AlertActionId = alertActionId
            }) as ObjectResult;
        // assert
        Assert.AreEqual(400, result.StatusCode);
        Assert.AreEqual("alertSchedule is not a valid integer", result.Value);
        _mockAlertDal.Verify(p => p.MarkAlertAction(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
    }
        [TestMethod]
        public async Task MarkAlertAction_DataLayerThrowsException_ReturnsError()
        {
            // setup
            var userId = 5;
            var alertSchedule = 7;
            var alertActionId = 9;
            _mockAlertDal.Setup(p => p.MarkAlertAction(alertSchedule,userId,alertActionId))
                .Throws(new Exception()).Verifiable();
            _alertController = new AlertController(_mockLogger.Object, _mapper, _mockAlertDal.Object, _mockOptions.Object);
            // execute
            var result = await _alertController.MarkAlertAction(alertSchedule.ToString(), userId.ToString(),new AlertActionViewModel()
            {
                   AlertActionId = alertActionId
            }) as ObjectResult;
            // assert
            Assert.AreEqual(500, result.StatusCode);
        }
    }
}