diff --git a/dumux/nonlinear/newtonsolver.hh b/dumux/nonlinear/newtonsolver.hh
index c130bb3f409a5e5f1a3268f57e383e5dbe9614d3..b6a46ae0d2f36381b180b50dbb29472ab7c2f336 100644
--- a/dumux/nonlinear/newtonsolver.hh
+++ b/dumux/nonlinear/newtonsolver.hh
@@ -205,20 +205,6 @@ public:
     void setMaxSteps(int maxSteps)
     { maxSteps_ = maxSteps; }
 
-    /*!
-     * \brief Run the Newton method to solve a non-linear system.
-     *        Does time step control when the Newton fails to converge
-     */
-    [[deprecated("Use attachConvergenceWriter(convWriter) and solve(x, *timeLoop) instead")]]
-    void solve(SolutionVector& uCurrentIter, TimeLoop& timeLoop,
-               std::shared_ptr<ConvergenceWriter> convWriter)
-    {
-        if (!convergenceWriter_)
-            attachConvergenceWriter(convWriter);
-
-        solve(uCurrentIter, timeLoop);
-    }
-
     /*!
      * \brief Run the Newton method to solve a non-linear system.
      *        Does time step control when the Newton fails to converge
@@ -684,20 +670,6 @@ public:
         return oldTimeStep*(1.0 + percent/1.2);
     }
 
-    /*!
-     * \brief Specifies if the Newton method ought to be chatty.
-     */
-    [[deprecated("Has been replaced by setVerbosity(int). Will be removed after 3.1 release!")]]
-    void setVerbose(bool val)
-    { verbosity_ = val; }
-
-    /*!
-     * \brief Returns true if the Newton method ought to be chatty.
-     */
-    [[deprecated("Has been replaced by int verbosity(). Will be removed after 3.1 release!")]]
-    bool verbose() const
-    { return verbosity_ ; }
-
     /*!
      * \brief Specifies the verbosity level
      */
@@ -992,8 +964,9 @@ private:
     void newtonUpdateShiftImpl_(const SolVec &uLastIter,
                                 const SolVec &deltaU)
     {
-        for (int i = 0; i < int(uLastIter.size()); ++i) {
-            typename SolVec::block_type uNewI = uLastIter[i];
+        for (int i = 0; i < int(uLastIter.size()); ++i)
+        {
+            auto uNewI = uLastIter[i];
             uNewI -= deltaU[i];
 
             Scalar shiftAtDof = relativeShiftAtDof_(uLastIter[i], uNewI);
@@ -1023,7 +996,6 @@ private:
                                    const SolutionVector &deltaU)
     {
         Scalar lambda = 1.0;
-        SolutionVector tmp(uLastIter);
 
         while (true)
         {
@@ -1082,7 +1054,7 @@ private:
         //! to this field vector type in Dune ISTL
         //! Could be avoided for vectors that already have the right type using SFINAE
         //! but it shouldn't impact performance too much
-        constexpr auto blockSize = JacobianMatrix::block_type::rows;
+        constexpr auto blockSize = std::decay_t<decltype(b[0])>::dimension;
         using BlockType = Dune::FieldVector<Scalar, blockSize>;
         Dune::BlockVector<BlockType> xTmp; xTmp.resize(b.size());
         Dune::BlockVector<BlockType> bTmp(xTmp);
diff --git a/test/nonlinear/CMakeLists.txt b/test/nonlinear/CMakeLists.txt
index 3640235bdcfbdd1b4fa0aacce2527f8cc8114bf9..7036b25e084f12339a751747c7321c19bf38b612 100644
--- a/test/nonlinear/CMakeLists.txt
+++ b/test/nonlinear/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(findscalarroot)
+add_subdirectory(newton)
diff --git a/test/nonlinear/newton/CMakeLists.txt b/test/nonlinear/newton/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4187ae5cab66a15cfa3ad925070af87a60174f10
--- /dev/null
+++ b/test/nonlinear/newton/CMakeLists.txt
@@ -0,0 +1,7 @@
+dumux_add_test(SOURCES test_newton.cc
+               LABELS unit nonlinear)
+dumux_add_test(NAME test_newton_linesearch
+               TARGET test_newton
+               COMMAND test_newton
+               CMD_ARGS "-Newton.UseLineSearch" "true"
+               LABELS unit nonlinear)
diff --git a/test/nonlinear/newton/test_newton.cc b/test/nonlinear/newton/test_newton.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5f37e2c3656bbdaa8f0574888023e0823139cd6b
--- /dev/null
+++ b/test/nonlinear/newton/test_newton.cc
@@ -0,0 +1,163 @@
+#include <config.h>
+
+#include <iostream>
+#include <cmath>
+#include <iomanip>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/float_cmp.hh>
+#include <dune/common/parallel/mpihelper.hh>
+#include <dumux/nonlinear/newtonsolver.hh>
+
+/*
+
+  This test currently solves a scalar non-linear equation using the
+  Dumux::NewtonSolver. The Mock classes expose which dependencies the
+  current implementation has on different other classes it interacts with.
+  Several dependencies seem unnecessary. In particular, the current
+  implementation is basically hard-coded to double indexable residual vectors
+  with several math operators. A good idea would seem to somehow delegate
+  this dependency to something like a linear algebra backend or at least
+  the assembler. The assembler requires a lot of interface functions which
+  are not always needed. The linear solver interdependency is much better (small).
+
+  This test is to ensure that the dependencies do not grow more in the future.
+
+ */
+
+namespace Dumux {
+
+class MockScalarVariables
+{
+public:
+    static constexpr int dimension = 1;
+    MockScalarVariables() : var_(0.0) {}
+    explicit MockScalarVariables(double v) : var_(v) {}
+    MockScalarVariables& operator-=(const MockScalarVariables& other) { var_ -= other.var_; return *this; }
+    double& operator[] (int i) { return var_; }
+    const double& operator[] (int i) const { return var_; }
+private:
+    double var_;
+};
+
+class MockScalarResidual
+{
+public:
+    MockScalarResidual() : res_(0.0) {}
+    explicit MockScalarResidual(double r) : res_(r) {}
+    MockScalarResidual& operator=(double r) { res_[0] = r; return *this; }
+    MockScalarResidual& operator*=(double a) { res_[0] *= a; return *this; }
+    MockScalarResidual& operator+=(const MockScalarResidual& other) { res_[0] += other.res_[0]; return *this; }
+    MockScalarResidual& operator-=(const MockScalarResidual& other) { res_[0] -= other.res_[0]; return *this; }
+    constexpr std::size_t size() const { return 1; }
+    MockScalarVariables& operator[] (int i) { return res_; }
+    const MockScalarVariables& operator[] (int i) const { return res_; }
+    double two_norm2() const { return res_[0]*res_[0]; }
+private:
+    MockScalarVariables res_;
+};
+
+class MockScalarAssembler
+{
+public:
+    using ResidualType = MockScalarResidual;
+    using Scalar = double;
+    using JacobianMatrix = double;
+
+    void setLinearSystem() {}
+
+    bool isStationaryProblem() { return false; }
+
+    ResidualType prevSol() { return ResidualType(0.0); }
+
+    void resetTimeStep(const ResidualType& sol) {}
+
+    void assembleResidual(const ResidualType& sol)
+    {
+        res_[0][0] = sol[0][0]*sol[0][0] - 5.0;
+    }
+
+    void assembleJacobianAndResidual (const ResidualType& sol)
+    {
+        assembleResidual(sol);
+        jac_ = 2.0*sol[0][0];
+    }
+
+    JacobianMatrix& jacobian() { return jac_; }
+
+    ResidualType& residual() { return res_; }
+
+    double residualNorm(const ResidualType& sol)
+    {
+        assembleResidual(sol);
+        return res_[0][0];
+    }
+
+    void updateGridVariables(const ResidualType& sol) {}
+
+private:
+    JacobianMatrix jac_;
+    ResidualType res_;
+};
+
+class MockScalarLinearSolver
+{
+public:
+    void setResidualReduction(double residualReduction) {}
+
+    template<class Vector>
+    bool solve (const double& A, Vector& x, const Vector& b) const
+    {
+        x[0][0] = b[0][0]/A;
+        return true;
+    }
+};
+
+} // end namespace Dumux
+
+int main(int argc, char* argv[]) try
+{
+    using namespace Dumux;
+
+    // maybe initialize MPI
+    Dune::MPIHelper::instance(argc, argv);
+
+    // initialize  parameters
+    // TODO this is necessary because there are some global default used in the Newton solver
+    // Do we really need them to be global defaults???
+    Parameters::init(argc, argv);
+
+    // use the Newton solver to find a solution to a scalar equation
+    using Assembler = MockScalarAssembler;
+    using LinearSolver = MockScalarLinearSolver;
+    using Solver = NewtonSolver<Assembler, LinearSolver, DefaultPartialReassembler>;
+
+    auto assembler = std::make_shared<Assembler>();
+    auto linearSolver = std::make_shared<LinearSolver>();
+    auto solver = std::make_shared<Solver>(assembler, linearSolver);
+
+    double initialGuess = 0.1;
+    MockScalarResidual x(initialGuess);
+
+    std::cout << "Solving: x^2 - 5 = 0" << std::endl;
+    solver->solve(x);
+    std::cout << "Solution: " << std::setprecision(15) << x[0][0]
+              << ", exact: " << std::sqrt(5.0)
+              << ", error: " << std::abs(x[0][0]-std::sqrt(5.0))/std::sqrt(5.0)*100 << "%" << std::endl;
+
+    if (Dune::FloatCmp::ne(x[0][0], std::sqrt(5.0), 1e-13))
+        DUNE_THROW(Dune::Exception, "Didn't find correct root: " << std::setprecision(15) << x[0][0] << ", exact: " << std::sqrt(5.0));
+
+    return 0;
+
+}
+catch (const Dune::Exception& e)
+{
+    std::cout << e << std::endl;
+    return 1;
+}
+catch (...)
+{
+    std::cout << "Unknown exception thrown!" << std::endl;
+    return 1;
+}