How to test a dynamically list properly - c#

I want to test that a bunch of buttons on screen are responding properly, this amount this increase dynamically thought the project and will be used in more than a single test.
My first try was using [TestCase] attribute
[TestCase("High action - Button")]
[TestCase("Low action - Button")]
[TestCase("Right action - Button")]
[TestCase("Left action - Button")]
public void WhenClickOnActionButtons_ActionStreamShouldIncrease (string buttonNameInScene)
But this means that every time that some buttons were added I would need to remember to come back to every test that use the buttons and manually add the new test case
Then I thought that have a container that control the buttons would solve my problem, I will lost the possibility to see which buttons caused the error in the test suite, but this can be fixed just by adding a simple message into the assert
[Test]
[Order(1)]
public IEnumerator WhenClickOnActionButtons_ActionStreamShouldIncrease ()
{
foreach (var battleActionButton in battleActionButtons) // <- Buttons containers
{
// Arrange
var changedWhenClicked = false;
battleActionButton.GetComponent<Button>().onClick.AddListener(() => changedWhenClicked = true);
// Act
var positionOfButtonInScreen = Camera.main.WorldToScreenPoint(battleActionButton.transform.position);
LeftClickOnScreenPosition(positionOfButtonInScreen);
yield return null;
// Assert
Assert.True(changedWhenClicked, $"{battleActionButton.name} didn't pressed correctly");
}
}
But now if the button container is empty the test pass, so I thought, let's create a test that runs before it to check if the container is empty
[Test]
[Order(0)]
public void ActionButtonsGroup_IsGreaterThan0()
{
// Arrange
// Act
// Assert
Assert.That(battleActionButtons.Count, Is.GreaterThan(0));
}
But then, if empty, this fails, and the next pass, so I thought, maybe I could make the tests stop running when a test fails, but then I discovered that a test should not rely on other tests, so my question is, how should I handle this kindle of case?

This sounds like a case for using a proper collection as a data source for a parametrised test. In NUnit you can use TestCaseSource for this:
[TestCaseSource(typeof(BattleActionButtons))]
public void ButtonTest(BattleActionButton button)
{
// Test body goes here...
}
where BattleActionButtons is a real class:
public sealed class BattleActionButtons : IReadOnlyCollection<BattleActionButton>
{
private readonly List<BattleActionButton> buttons = new();
public BattleActionButtons()
{
// Add buttons here...
}
public int Count => buttons.Count;
public IEnumerator<BattleActionButton> GetEnumerator()
{
return buttons.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Perhaps BattleActionButtons is just a test-specific class, but perhaps it would make sense in the production code as well..(?) With TDD, it often happens that you introduce an abstraction to factor your tests in a nice way, only to discover that this abstraction is of general usefulness.
If you're concerned that BattleActionButtons is empty, write another test that verifies that this isn't the case:
[Test]
public void ButtonsAreNotEmpty()
{
Assert.IsNotEmpty(new BattleActionButtons());
}
There's no need to order the tests. If BattleActionButtons is empty, ButtonsAreNotEmpty will fail. It's true that the data-driven parametrised test (here called ButtonTest) will pass when the collection is empty, but there's nothing wrong in that. It just becomes a vacuous truth.
(Unit tests are essentially predicates, and a parametrised test is a universal claim that states that for all (∀) values in the data source, the predicate holds. Thus, when the data source is empty, any test is trivially going to pass, which is exactly as it should be according to predicate logic.)

You can put the assertion from the second test before the foreach loop:
[Test]
[Order(1)]
public IEnumerator WhenClickOnActionButtons_ActionStreamShouldIncrease ()
{
// Precondition
Assert.That(battleActionButtons.Count, Is.GreaterThan(0));
foreach (var battleActionButton in battleActionButtons) // <- Buttons containers
{
// Arrange
var changedWhenClicked = false;
battleActionButton.GetComponent<Button>().onClick.AddListener(() => changedWhenClicked = true);
// Act
var positionOfButtonInScreen = Camera.main.WorldToScreenPoint(battleActionButton.transform.position);
LeftClickOnScreenPosition(positionOfButtonInScreen);
yield return null;
// Assert
Assert.True(changedWhenClicked, $"{battleActionButton.name} didn't pressed correctly");
}
}

Related

How does one set a variable in a command using Mediatr with Moq?

I have a simple functional style test for output of a command that I've written using Mediatr's IRequest and IRequestHandler<>
[Fact]
public void TestReturnValuesAsync()
{
// Arrange
var handler = new Mock<IRequestHandler<SyncSubmerchantDataCommand, CommandResult<int>>>();
handler.Setup(x => x.Handle(It.IsAny<SyncSubmerchantDataCommand>(), It.IsAny<CancellationToken>())).ReturnsAsync(new CommandResult<int>(0, ResultStatus.Success, "string"));
// Act
var result = handler.Object.Handle(new SyncSubmerchantDataCommand(), new CancellationToken());
// Assert
result.Result.Data.ShouldBe(0);
result.Result.Status.ShouldBe(ResultStatus.Success);
result.Result.Message.ShouldBe("string");
}
Since this command runs as a background task, I don't want it interrupted. I have a variable, submerchantList, that is of type List<T> which is used in a foreach loop to do work. The work is set in a try-catch because I don't want the command interrupted, as I stated before. I want to test the output of the what is written to my logs (_log.info) if an exception is thrown during this process.
public class CommandNameHandler : IRequestHandler<source, destination> {
// constructors and privates
public async destination Handle(param, token)
{
var submerchantList = db call.ToList();
foreach (var item in submerchantList)
{
try {
//does work
}
catch (Exception e) {
if (item != null)
_log.info($"{e} - {item.Id}");
}
return some out put
}
The problem is that I can't seem to figure out how to set the value of the any variable, such as the submerchantList within the Handle in order to throw the exception for my next test. I'm stumped.
Any help would be greatly appreciated.
SOLUTION:
Here was the solution: Stubbing the database call by injecting an in-memory DbSet. I used this resource learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/… This issue was db call.ToList It looked something like this _db.Table.Include(x => x.Foreign).Where(x => x.Foreign.Field == Enum.Value).ToListAsync() While I was setting up the Mock DbSet, I had to use the string version, not the LINQ-chain version in the unit test. So, that means mockDbset.Setup(x => x.Table.Include("Foreign")).Returns(myCustomDbSet); Hope that helps someone!

Integration tests - what would you test for in this controller?

I'm applying NUnit integration tests on our controller endpoints in a .NET Web API 2 project whose models and controllers are generated via Entity code first from database.
I'm having trouble thinking of what parts of the controller I should test. In the end, we'd just like to be able to automate "can a user with "x" role get this data?"
Looking in the GET portion of this controller, what parts would you test and what's your reasoning?
namespace api.Controllers.myNamespace
{
public class myController : ApiController
{
private string strUserName;
private string strError = "";
private string strApiName = "myTable";
private myDatabase db = new myDatabase();
// ----------------------------------------------------------------------
// GET: api/path
public IQueryable<myTable> GetmyTable()
{
try
{
this.strUserName = this.getUserName();
if
(
// ----- authorize -----
db.view_jnc_role_api_permission.Count
(
view =>
(
view.permission == "get"
&& view.apiName == this.strApiName
&& view.userName == this.strUserName
)
) == 1
// ----- /authorize -----
)
{
// ----- get -----
IQueryable<myTable> data =
from tbl in db.myTable
where tbl.deleted == null
select tbl;
// ----- /get -----
return data;
}
else
{
strError = "Unauthorized.";
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
catch (Exception ex)
{
if (strError.Length == 0)
{
if (this.showException())
{
strError = ex.ToString();
}
}
throw new HttpResponseException(ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, strError));
}
}
}
For reference, here's what I have so far. Some of these private fields I'm defining shouldn't be here - currently trying to get access to private methods from my test project via AssemblyInfo.cs to fix this:
namespace api.myNamespace
{
[TestFixture]
public class myController : ApiController
{
private string strUserName;
private string strError = "";
private string strApiName = "myTable";
private myDb db = new myDb();
// Using TransactionScope to (hopefully) prevent integration test's changes to database from persisting
protected TransactionScope TransactionScope;
// Instantiate _controller field
private myController _controller;
[SetUp]
public void SetUp() {
TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
// It's possible that one test may leave some state which could impact subsequent tests - so we must reinstantiate _controller at the start of each new test:
_controller = new myController();
}
[TearDown]
public void TearDown()
{
TransactionScope.Dispose();
}
**//------ TESTS -------//
// CanSetAndGetUserName
// AuthorizedUserCanGetData
// UnauthorizedUserCannotGetData
// AuthorizedUserCanPutData
// UnauthorizedUserCannotPutData
// AuthorizedUserCanPostData
// UnauthorizedUserCannotPostData
// AuthorizedUserCanDeleteData
// UnauthorizedUserCannotDeleteData**
[Test]
public void CanGetAndSetUsername()
{
// ARRANGE
var user = _controller.getUserName();
// ACT
// ASSERT
Assert.That(user, Is.EqualTo("my-internal-username"));
}
[Test]
public void UnauthorizedUserCannotGetData()
{
var user = "Mr Unauthorized";
// Unfinished bc integration testing is super abstract, subjective, hard, time consuming and hard. All downvoters are plebs.
Assert.That(user, Is.EqualTo());
}
}
}
}
integration tests means several things:
you setup your test data in the database, via a script for example.
you call the endpoint under test knowing exactly what data you should call it with and what you should get. This is all based on your test data you setup in step 1.
you compare your expected data with the one you got back.
this is an integration test as it touches everything, both api and database.
Now, you said you are having trouble deciding which parts of the controller to test. This suggests you are confusing integration tests with unit tests.
Integration tests we already covered.
Unit tests cover parts of functionality. You do not test controllers, forget about that.
What you really need to consider doing is this:
First, separate your code from the controller. Keep the controller very basic. It receives a call, validates the request model and passes it further to a class library where the functionality happens. This allows you to forget "testing the controller" and focus on your functionality instead. Unit tests will help here and your test cases will become something like this
I have a user, set up in a certain way.
I have some data, set up in a certain way
When I call method X, then I should get this response.
With such a setup in place, you can set your test data any way you like and check every single test case.
The only reason you wonder how you test your controller is because you dumped all your code into it, which of course makes everything hard. Think SOLID, think SOC ( Separation of concerns ).
One piece of advice: never ever return IQueryable from an endpoint, that's not data, that simply a query that hasn't run yet. Return a List, IEnumerable, an singular object, whatever you need, just make sure you execute that first by calling ToList() for example on your IQueryable expression first.
So, the steps are like this:
Setup your IQueryable first
Execute it by calling ToList(), First(), FirstOrDefault() whatever is appropriate and return the result of that.

Testing with moq

I'm trying to work out this whole testing thing, and have decided to start with an existing application that we use to record phone calls to the office. The app is a c#, mvvm, desktop application and for now at least, I'm just trying to work out how the testing framework operates. I have created a new test project, added reference to moq and am trying to run a test that verifies a method is called by another method.
The method I'm testing is simply a Command to close a window. The command uses messaging to communicate with a View Service to actually do the closing. Relevant code:
BaseViewModel:
public RelayCommand CloseWindowCommand { get; set; }
public BaseViewModel(IDataAccessService dataAccess)
{
...
CloseWindowCommand = new RelayCommand(CloseWindow);
}
internal virtual void CloseWindow()
{
SendCloseRequest();
}
void SendCloseRequest()
{
System.Windows.MessageBox.Show("called BaseVM.SendCloseRequest");
Messenger.Default.Send<RequestCloseMessage>(new RequestCloseMessage(this), this);
}
ViewService:
private Window CreateWindow(ViewModelBase vm)
{
...
window.DataContext = vm;
window.Closed += OnClosed;
// listen for the close event
Messenger.Default.Register<RequestCloseMessage>(window, vm, OnRequestClose);
return window;
}
public void OnRequestClose(RequestCloseMessage message)
{
System.Windows.MessageBox.Show("called ViewService.OnRequestClose");
var window = OpenedWindows.SingleOrDefault(w => w.DataContext == message.ViewModel);
if (window != null)
{
Messenger.Default.Unregister<RequestCloseMessage>(window, message.ViewModel, OnRequestClose);
if (message.DialogResult != null)
{
// trying to set the dialog result of the non-modal window will result in InvalidOperationException
window.DialogResult = message.DialogResult;
}
window.Close();
}
}
BaseViewModelTest (1):
[TestMethod]
public void SendCloseMesage_Calls_OnRequestClose()
{
Mock<IDataAccessService> mockProxy = new Mock<IDataAccessService>();
Mock<IViewService> mockView = new Mock<IViewService>();
var vm = new BaseViewModel(mockProxy.Object);
Mock<RequestCloseMessage> mockCloseMessage = new Mock<RequestCloseMessage>((ViewModelBase)vm, null);
vm.CloseWindowCommand.Execute(null);
mockView.Verify(v => v.OnRequestClose(mockCloseMessage.Object));
}
When I run the test it fails with:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: v => v.OnRequestClose
So, I tried to just test that the command calls the method in the VM:
BaseViewModelTest (2):
[TestMethod]
public void SendCloseMesage_Calls_CloseWindow()
{
Mock<IDataAccessService> mockProxy = new Mock<IDataAccessService>();
Mock<IViewService> mockView = new Mock<IViewService>();
//var vm = new BaseViewModel(mockProxy.Object);
Mock<BaseViewModel> mockVM = new Mock<BaseViewModel>(mockProxy);
Mock<RequestCloseMessage> mockCloseMessage = new Mock<RequestCloseMessage>((ViewModelBase)mockVM.Object, null);
mockVM.Object.CloseWindowCommand.Execute(null);
mockVM.Verify(vm => vm.CloseWindow());
}
This comes back with a similar error:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: vm => vm.CloseWindow()
However, in both cases, the System.Windows.MessageBox.Show("called <MethodName>"); statement is called as I have to deal with the dialog box. (I added the MessageBox commands for confirmation. The error is the same with or without them.)
Why is Moq telling me the method isn't called, when the MessageBox.Show() command in the method is being called?
PS: I'm not overly worried about whether testing the window closes is worth it, at the moment, I'm just trying to make sure I can test one method is calling another.
First of all, method MessageBox.Show is a static method. If you call it directly, Moq has no chance of knowing that.
In addition, do you even pass (or inject) your mockCloseMessage to your subject-under-test?
mockView.Verify(v => v.OnRequestClose(mockCloseMessage.Object));
This will verify that OnRequestClose was called at least once with the instance mockCloseMessage.Object, which seems not true in your case.
You should use It.IsAny<>() (or another mathing argument function, check the docs):
mockView.Verify(v => v.OnRequestClose(It.IsAny<RequestCloseMessage>()));
Update
After looking again at your code, there are some other points to mention:
The idea of mocking is when you would like to test a specific class that is dependent on other classes. Then, you would mock those dependencies classes in order to isolate and simplify your test.
It seems that you have created some mocks, but they are not injected to the object you are testing.
Another issue is that you have a dependency upon the Messenger class and a registration procedure has to be done, in order for the service to receive the event. You are mixing too much here, and make assumptions. To me, it seems that you are missing the whole point of unit test. Your test relies on actions that happens elsewhere.
Your code as is, doesn't seem easy to test.

rhinomocks setting expectation, unit test always passes

I'm trying to become more familiar with the Rhinomocks framework, and I'm trying to understand the Expect methods of rhinomocks.
Here's a unit test I have written:
[TestMethod]
public void Create_ValidModelData_CreatesNewEventObjectWithGivenSlugId()
{
//Arrange
var eventList = new List<Event>() { new Event() { Slug = "test-user" } };
_stubbedEventRepository.Stub(x => x.GetEvents())
.Return(eventList);
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()))
.Repeat
.Once();
var controller = new EventController(_stubbedEventRepository);
EventViewModel model = new EventViewModel();
//Act
//controller.Create(model); COMMENTED OUT
//Assert
_stubbedEventRepository.VerifyAllExpectations();
}
I thought I understood this code to only pass if the SaveEvent(...) method get's called exactly once. However, with controller.Create(model) commented out, the test still passes. Inside controller.Create(model) is where the SaveEvent() method gets called.
I tried the following:
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()));
But it still passes every time, so what am I doing incorrectly stack overflow? The sources I have looked at online haven't been able to help me. Why is VerifyAllExpectations() yielding a successful unit test?
Thank you!
Here's the body of the controller constructor:
public EventController(IEventRepository eventRepository)
{
_eventRepository = eventRepository;
}
edit:
// member variables
private IEventRepository _stubbedEventRepository;
[TestInitialize]
public void SetupTests()
{
_stubbedEventRepository = MockRepository.GenerateStub<IEventRepository>();
}
If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.

Retry a Visual Studio C# TestMethod

I'm curious to know if there's any built-in mechanism to retry tests in the Visual Studio 2008 unit testing framework for C#.
Case in point, I have a C# unit test which looks something like:
[TestMethod]
public void MyMethod() {
DoSomething();
Assert.Something();
}
Now, occasionally DoSomething() performs badly; in that case I would like to rerun the DoSomething() method before reaching the assertion. Obviously I can do something like:
...
do {
Initialization();
DoSomething();
} while (PerformedOK() == false);
Assert.Something();
...
Though this is a bit cumbersome because of the added loop and repeating the test initialization which would otherwise be completely handled by other methods / class constructor.
My question is whether there is a more convenient mechanism for retrying a test, something like:
DoSomething();
if (PerformedOK() == false) Retry();
else Assert.Something();
which will automatically retry the test without registering it as a failure, while performing all the regular initialization code as usual.
Seriously...
occasionally DoSomething() performs
badly
A test should be green every time. If the tested code sometimes perform "badly", then you need to fix your code, isolating the different behavior. You should have two test, one where it Asserts correct when DoSomething fails (and is supposed to fail), and one where it Asserts correct when DoSomething is ok (and is supposed to be ok).
Having retry logic in a test is just wrong imo. You should always Assert on the expected outcome, and you should be able to isolate and instrument your code to return what you expect.
[Edit - added some code which could be used for a retry loop]
You could create a loop wrapper which takes whatever method in and calls it X number of times, or until it succeeds. You could also have the Loop function call your init, or pass it as a separate argument. The method could also return a bool if successful. Change the signature to fit your needs.
[TestMethod]
public void something()
{
Loop.LoopMe(TestMethod,3);
Assert.Something();
}
class Loop
{
public static void LoopMe(Action action, int maxRetry)
{
Exception lastException = null;
while (maxRetry > 0)
{
try
{
action();
return;
}
catch (Exception e)
{
lastException = e;
maxRetry--;
}
}
throw lastException;
}
}
Your second example is almost the same lines of code and same complexity. There are tons of ways to skin it, you could not that I am advocating it use recursion.
[TestMethod]
public void MyMethod() {
bool success = DoSomething();
Assert.IsTrue(success);
}
public boolean DoSomething(){
//Do whatever
if(performedOk){
return true;
}else{
//find a way to stop it.
}
}
But the point is it is a unit test. If something is causing it to go wrong, you need to find a way isolate your test, so that it is in a controlled environment.
Unless you have a requirement that says, test should pass eventually. The best retry logic you should use, is after it fails. Click the test and hit run again.

Categories

Resources